<!DOCTYPE html><html lang="zh-CN" data-theme="light"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"><title>Spring框架 | zylai</title><meta name="keywords" content="框架,Spring,Spring Framework"><meta name="author" content="zylai"><meta name="copyright" content="zylai"><meta name="format-detection" content="telephone=no"><meta name="theme-color" content="#ffffff"><meta name="description" content="Spring 1 Spring简介👾 1.1 Spring概述   Spring 是最受欢迎的企业级 Java 应用程序开发框架，数以百万的来自世界各地的开发人员使用 Spring 框架来创建性能好、易于测试、可重用的代码。 Spring 框架是一个开源的 Java 平台，它最初是由 Rod Johnson 编写的，并且于 2003 年 6 月首 次在 Apache 2.0 许可下发布。 Spr">
<meta property="og:type" content="article">
<meta property="og:title" content="Spring框架">
<meta property="og:url" content="https://zhaoyunlai.gitee.io/posts/d438b6f1fced/index.html">
<meta property="og:site_name" content="zylai">
<meta property="og:description" content="Spring 1 Spring简介👾 1.1 Spring概述   Spring 是最受欢迎的企业级 Java 应用程序开发框架，数以百万的来自世界各地的开发人员使用 Spring 框架来创建性能好、易于测试、可重用的代码。 Spring 框架是一个开源的 Java 平台，它最初是由 Rod Johnson 编写的，并且于 2003 年 6 月首 次在 Apache 2.0 许可下发布。 Spr">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://zylai-cloud-pic-1306915061.cos.ap-nanjing.myqcloud.com/images01/Spring.assets/image-20220724093300702.png">
<meta property="article:published_time" content="2022-08-02T11:39:22.000Z">
<meta property="article:modified_time" content="2022-08-04T13:16:53.183Z">
<meta property="article:author" content="zylai">
<meta property="article:tag" content="框架">
<meta property="article:tag" content="Spring">
<meta property="article:tag" content="Spring Framework">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://zylai-cloud-pic-1306915061.cos.ap-nanjing.myqcloud.com/images01/Spring.assets/image-20220724093300702.png"><link rel="shortcut icon" href="/img/favicon.png"><link rel="canonical" href="https://zhaoyunlai.gitee.io/posts/d438b6f1fced/"><link rel="preconnect" href="//cdn.jsdelivr.net"/><link rel="preconnect" href="//hm.baidu.com"/><link rel="preconnect" href="//busuanzi.ibruce.info"/><link rel="stylesheet" href="/css/index.css"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free/css/all.min.css" media="print" onload="this.media='all'"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fancyapps/ui/dist/fancybox.min.css" media="print" onload="this.media='all'"><script>var _hmt = _hmt || [];
(function() {
  var hm = document.createElement("script");
  hm.src = "https://hm.baidu.com/hm.js?ec7714e43e379e663d7258bb72abd0cc";
  var s = document.getElementsByTagName("script")[0]; 
  s.parentNode.insertBefore(hm, s);
})();
</script><script>const GLOBAL_CONFIG = { 
  root: '/',
  algolia: undefined,
  localSearch: {"path":"/search.xml","preload":false,"languages":{"hits_empty":"找不到您查询的内容：${query}"}},
  translate: undefined,
  noticeOutdate: undefined,
  highlight: {"plugin":"highlighjs","highlightCopy":true,"highlightLang":true,"highlightHeightLimit":false},
  copy: {
    success: '复制成功',
    error: '复制错误',
    noSupport: '浏览器不支持'
  },
  relativeDate: {
    homepage: false,
    post: false
  },
  runtime: '',
  date_suffix: {
    just: '刚刚',
    min: '分钟前',
    hour: '小时前',
    day: '天前',
    month: '个月前'
  },
  copyright: undefined,
  lightbox: 'fancybox',
  Snackbar: undefined,
  source: {
    justifiedGallery: {
      js: 'https://cdn.jsdelivr.net/npm/flickr-justified-gallery/dist/fjGallery.min.js',
      css: 'https://cdn.jsdelivr.net/npm/flickr-justified-gallery/dist/fjGallery.min.css'
    }
  },
  isPhotoFigcaption: false,
  islazyload: false,
  isAnchor: false
}</script><script id="config-diff">var GLOBAL_CONFIG_SITE = {
  title: 'Spring框架',
  isPost: true,
  isHome: false,
  isHighlightShrink: false,
  isToc: true,
  postUpdate: '2022-08-04 21:16:53'
}</script><noscript><style type="text/css">
  #nav {
    opacity: 1
  }
  .justified-gallery img {
    opacity: 1
  }

  #recent-posts time,
  #post-meta time {
    display: inline !important
  }
</style></noscript><script>(win=>{
    win.saveToLocal = {
      set: function setWithExpiry(key, value, ttl) {
        if (ttl === 0) return
        const now = new Date()
        const expiryDay = ttl * 86400000
        const item = {
          value: value,
          expiry: now.getTime() + expiryDay,
        }
        localStorage.setItem(key, JSON.stringify(item))
      },

      get: function getWithExpiry(key) {
        const itemStr = localStorage.getItem(key)

        if (!itemStr) {
          return undefined
        }
        const item = JSON.parse(itemStr)
        const now = new Date()

        if (now.getTime() > item.expiry) {
          localStorage.removeItem(key)
          return undefined
        }
        return item.value
      }
    }
  
    win.getScript = url => new Promise((resolve, reject) => {
      const script = document.createElement('script')
      script.src = url
      script.async = true
      script.onerror = reject
      script.onload = script.onreadystatechange = function() {
        const loadState = this.readyState
        if (loadState && loadState !== 'loaded' && loadState !== 'complete') return
        script.onload = script.onreadystatechange = null
        resolve()
      }
      document.head.appendChild(script)
    })
  
      win.activateDarkMode = function () {
        document.documentElement.setAttribute('data-theme', 'dark')
        if (document.querySelector('meta[name="theme-color"]') !== null) {
          document.querySelector('meta[name="theme-color"]').setAttribute('content', '#0d0d0d')
        }
      }
      win.activateLightMode = function () {
        document.documentElement.setAttribute('data-theme', 'light')
        if (document.querySelector('meta[name="theme-color"]') !== null) {
          document.querySelector('meta[name="theme-color"]').setAttribute('content', '#ffffff')
        }
      }
      const t = saveToLocal.get('theme')
    
          if (t === 'dark') activateDarkMode()
          else if (t === 'light') activateLightMode()
        
      const asideStatus = saveToLocal.get('aside-status')
      if (asideStatus !== undefined) {
        if (asideStatus === 'hide') {
          document.documentElement.classList.add('hide-aside')
        } else {
          document.documentElement.classList.remove('hide-aside')
        }
      }
    
    const detectApple = () => {
      if(/iPad|iPhone|iPod|Macintosh/.test(navigator.userAgent)){
        document.documentElement.classList.add('apple')
      }
    }
    detectApple()
    })(window)</script><!-- hexo injector head_end start --><link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/Zfour/hexo-electric-clock@1.0.6/clock.css"><!-- hexo injector head_end end --><meta name="generator" content="Hexo 5.4.2"></head><body><div id="web_bg"></div><div id="sidebar"><div id="menu-mask"></div><div id="sidebar-menus"><div class="avatar-img is-center"><img src="/img/avatar.jpg" onerror="onerror=null;src='/img/friend_404.gif'" alt="avatar"/></div><div class="sidebar-site-data site-data is-center"><a href="/archives/"><div class="headline">文章</div><div class="length-num">18</div></a><a href="/tags/"><div class="headline">标签</div><div class="length-num">14</div></a><a href="/categories/"><div class="headline">分类</div><div class="length-num">11</div></a></div><hr/><div class="menus_items"><div class="menus_item"><a class="site-page" href="/"><i class="fa-fw fas fa-home"></i><span> 首页</span></a></div><div class="menus_item"><a class="site-page" href="/archives/"><i class="fa-fw fas fa-archive"></i><span> 时间轴</span></a></div><div class="menus_item"><a class="site-page" href="/tags/"><i class="fa-fw fas fa-tags"></i><span> 标签</span></a></div><div class="menus_item"><a class="site-page" href="/categories/"><i class="fa-fw fas fa-folder-open"></i><span> 分类</span></a></div><div class="menus_item"><a class="site-page" href="/link/"><i class="fa-fw fas fa-link"></i><span> 友链</span></a></div><div class="menus_item"><a class="site-page" href="/about/"><i class="fa-fw fas fa-heart"></i><span> 关于</span></a></div></div></div></div><div class="post" id="body-wrap"><header class="post-bg" id="page-header" style="background-image: url('https://zylai-cloud-pic-1306915061.cos.ap-nanjing.myqcloud.com/images01/Spring.assets/image-20220724093300702.png')"><nav id="nav"><span id="blog_name"><a id="site-name" href="/">zylai</a></span><div id="menus"><div id="search-button"><a class="site-page social-icon search"><i class="fas fa-search fa-fw"></i><span> 搜索</span></a></div><div class="menus_items"><div class="menus_item"><a class="site-page" href="/"><i class="fa-fw fas fa-home"></i><span> 首页</span></a></div><div class="menus_item"><a class="site-page" href="/archives/"><i class="fa-fw fas fa-archive"></i><span> 时间轴</span></a></div><div class="menus_item"><a class="site-page" href="/tags/"><i class="fa-fw fas fa-tags"></i><span> 标签</span></a></div><div class="menus_item"><a class="site-page" href="/categories/"><i class="fa-fw fas fa-folder-open"></i><span> 分类</span></a></div><div class="menus_item"><a class="site-page" href="/link/"><i class="fa-fw fas fa-link"></i><span> 友链</span></a></div><div class="menus_item"><a class="site-page" href="/about/"><i class="fa-fw fas fa-heart"></i><span> 关于</span></a></div></div><div id="toggle-menu"><a class="site-page"><i class="fas fa-bars fa-fw"></i></a></div></div></nav><div id="post-info"><h1 class="post-title">Spring框架</h1><div id="post-meta"><div class="meta-firstline"><span class="post-meta-date"><i class="far fa-calendar-alt fa-fw post-meta-icon"></i><span class="post-meta-label">发表于</span><time class="post-meta-date-created" datetime="2022-08-02T11:39:22.000Z" title="发表于 2022-08-02 19:39:22">2022-08-02</time><span class="post-meta-separator">|</span><i class="fas fa-history fa-fw post-meta-icon"></i><span class="post-meta-label">更新于</span><time class="post-meta-date-updated" datetime="2022-08-04T13:16:53.183Z" title="更新于 2022-08-04 21:16:53">2022-08-04</time></span><span class="post-meta-categories"><span class="post-meta-separator">|</span><i class="fas fa-inbox fa-fw post-meta-icon"></i><a class="post-meta-categories" href="/categories/Spring/">Spring</a></span></div><div class="meta-secondline"><span class="post-meta-separator">|</span><span class="post-meta-pv-cv" id="" data-flag-title="Spring框架"><i class="far fa-eye fa-fw post-meta-icon"></i><span class="post-meta-label">阅读量:</span><span id="busuanzi_value_page_pv"><i class="fa-solid fa-spinner fa-spin"></i></span></span></div></div></div></header><main class="layout" id="content-inner"><div id="post"><article class="post-content" id="article-container"><h1>Spring</h1>
<h2 id="1-Spring简介👾">1 Spring简介👾</h2>
<h3 id="1-1-Spring概述">1.1 Spring概述</h3>
<p><img src="https://zylai-cloud-pic-1306915061.cos.ap-nanjing.myqcloud.com/images01/Spring.assets/image-20220724093300702.png" alt="image-20220724093300702"></p>
<blockquote>
<p>Spring 是最受欢迎的企业级 Java 应用程序开发框架，数以百万的来自世界各地的开发人员使用<br>
Spring 框架来创建性能好、易于测试、可重用的代码。<br>
Spring 框架是一个开源的 Java 平台，它最初是由 Rod Johnson 编写的，并且于 2003 年 6 月首<br>
次在 Apache 2.0 许可下发布。<br>
Spring 是轻量级的框架，其基础版本只有 2 MB 左右的大小。<br>
Spring 框架的核心特性是可以用于开发任何 Java 应用程序，但是在 Java EE 平台上构建 web 应<br>
用程序是需要扩展的。 Spring 框架的目标是使 J2EE 开发变得更容易使用，通过启用基于 POJO<br>
编程模型来促进良好的编程实践。</p>
</blockquote>
<h3 id="1-2-Spring-Framework">1.2 Spring Framework</h3>
<p>Spring 基础框架，可以视为 Spring 基础设施，基本上任何其他 Spring 项目都是以 Spring Framework<br>
为基础的。</p>
<h4 id="1-2-1-Spring-Framework特性">1.2.1 Spring Framework特性</h4>
<p>1、非侵入式：使用 Spring Framework 开发应用程序时，Spring 对应用程序本身的结构影响非常<br>
小。对领域模型可以做到零污染；对功能性组件也只需要使用几个简单的注解进行标记，完全不会<br>
破坏原有结构，反而能将组件结构进一步简化。这就使得基于 Spring Framework 开发应用程序<br>
时结构清晰、简洁优雅。<br>
2、控制反转：IOC——Inversion of Control，翻转资源获取方向。把自己创建资源、向环境索取资源<br>
变成环境将资源准备好，我们享受资源注入。<br>
3、面向切面编程：AOP——Aspect Oriented Programming，在不修改源代码的基础上增强代码功<br>
能。<br>
4、容器：Spring IOC 是一个容器，因为它包含并且管理组件对象的生命周期。组件享受到了容器化<br>
的管理，替程序员屏蔽了组件创建过程中的大量细节，极大的降低了使用门槛，大幅度提高了开发<br>
效率。<br>
5、组件化：Spring 实现了使用简单的组件配置组合成一个复杂的应用。在 Spring 中可以使用 XML<br>
和 Java 注解组合这些对象。这使得我们可以基于一个个功能明确、边界清晰的组件有条不紊的搭<br>
建超大型复杂应用系统。<br>
声明式：很多以前需要编写代码才能实现的功能，现在只需要声明需求即可由框架代为实现。<br>
一站式：在 IOC 和 AOP 的基础上可以整合各种企业应用的开源框架和优秀的第三方类库。而且<br>
Spring 旗下的项目已经覆盖了广泛领域，很多方面的功能性需求可以在 Spring Framework 的基<br>
础上全部使用 Spring 来实现。</p>
<h4 id="1-2-2-Spring-Framework五大功能模块">1.2.2 Spring Framework五大功能模块</h4>
<p>功能模块功能介绍<br>
Core Container 核心容器，在 Spring 环境下使用任何功能都必须基于 IOC 容器。<br>
AOP&amp;Aspects 面向切面编程<br>
Testing 提供了对 junit 或 TestNG 测试框架的整合。<br>
Data Access/Integration 提供了对数据访问/集成的功能。<br>
Spring MVC 提供了面向Web应用程序的集成功能。</p>
<h2 id="2-IOC-IOC容器思想">2 IOC-IOC容器思想</h2>
<p>先简单说一下，IOC容器就是放置已经创建好的实例的一个地方。这样实例不需要程序员来手动创建，而是交给容器管理，更加高效。</p>
<blockquote>
<p>下面这一部分更加详细阐述了，如果要深入了解IOC容器，需要阅读源码，这个以后安排上。这个笔记主要用于学习如何使用框架</p>
</blockquote>
<h4 id="IOC容器思想">IOC容器思想</h4>
<p>IOC：Inversion of Control，翻译过来是反转控制。<br>
①获取资源的传统方式<br>
自己做饭：买菜、洗菜、择菜、改刀、炒菜，全过程参与，费时费力，必须清楚了解资源创建整个过程中的全部细节且熟练掌握。<br>
在应用程序中的组件需要获取资源时，传统的方式是组件主动的从容器中获取所需要的资源，在这样的模式下开发人员往往需要知道在具体容器中特定资源的获取方式，增加了学习成本，同时降低了开发效率。</p>
<p>②反转控制方式获取资源<br>
点外卖：下单、等、吃，省时省力，不必关心资源创建过程的所有细节。<br>
反转控制的思想完全颠覆了应用程序组件获取资源的传统方式：反转了资源的获取方向——改由容器主动的将资源推送给需要的组件，开发人员不需要知道容器是如何创建资源对象的，只需要提供接收资源的方式即可，极大的降低了学习成本，提高了开发的效率。这种行为也称为查找的被动形式。<br>
③DI<br>
DI：Dependency Injection，翻译过来是依赖注入。<br>
DI 是 IOC 的另一种表述方式：即组件以一些预先定义好的方式（例如：setter 方法）接受来自于容器的资源注入。相对于IOC而言，这种表述更直接。<br>
所以结论是：IOC 就是一种反转控制的思想， 而 DI 是对 IOC 的一种具体实现。</p>
<h4 id="IOC在Spring中的实现">IOC在Spring中的实现</h4>
<p>Spring 的 IOC 容器就是 IOC 思想的一个落地的产品实现。IOC 容器中管理的组件也叫做 bean。在创建bean 之前，首先需要创建 IOC 容器。Spring 提供了 IOC 容器的两种实现方式：<br>
①BeanFactory<br>
这是 IOC 容器的基本实现，是 Spring 内部使用的接口。面向 Spring 本身，不提供给开发人员使用。<br>
②ApplicationContext<br>
BeanFactory 的子接口，提供了更多高级特性。面向 Spring 的使用者，几乎所有场合都使用<br>
ApplicationContext 而不是底层的 BeanFactory。</p>
<p><img src="https://zylai-cloud-pic-1306915061.cos.ap-nanjing.myqcloud.com/images01/Spring.assets/image-20220725161008451.png" alt="image-20220725161008451"></p>
<h2 id="3-IOC-基于XML文件管理Bean">3 IOC-基于XML文件管理Bean</h2>
<p><strong>对于xml文件的方式也要学会掌握，因为对于工程里面的一些jar包，你是无法在上面给他加注释的，只是使用xml文件方式。</strong></p>
<h3 id="3-1-准备工作">3.1 准备工作</h3>
<p>maven依赖：</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dependencies</span>&gt;</span></span><br><span class="line">    <span class="comment">&lt;!-- 基于Maven依赖传递性，导入spring-context依赖即可导入当前所需所有jar包 --&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-context<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">version</span>&gt;</span>5.3.1<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="comment">&lt;!-- junit测试 --&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>junit<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>junit<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">version</span>&gt;</span>4.12<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">scope</span>&gt;</span>test<span class="tag">&lt;/<span class="name">scope</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependencies</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p><img src="https://zylai-cloud-pic-1306915061.cos.ap-nanjing.myqcloud.com/images01/Spring.assets/image-20220803161905754.png" alt="image-20220803161905754"></p>
<p>创建Spring的配置文件：</p>
<p><img src="https://zylai-cloud-pic-1306915061.cos.ap-nanjing.myqcloud.com/images01/Spring.assets/image-20220803161959462.png" alt="image-20220803161959462"></p>
<h3 id="3-2-获取bean">3.2 获取bean</h3>
<h4 id="3-2-1-方式一：通过bean的id">3.2.1 方式一：通过bean的id</h4>
<p>配置文件中：</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;studentOne&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.zylai.spring.pojo.Student&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;studentTwo&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.zylai.spring.pojo.Student&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>测试：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Test</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">testIOC</span><span class="params">()</span>&#123;</span><br><span class="line">        <span class="type">ApplicationContext</span> <span class="variable">ioc</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ClassPathXmlApplicationContext</span>(<span class="string">&quot;spring-ioc.xml&quot;</span>);</span><br><span class="line">        <span class="comment">//获取bean</span></span><br><span class="line"><span class="comment">//        1.通过bean的id获取</span></span><br><span class="line">        <span class="type">Student</span> <span class="variable">studentOne</span> <span class="operator">=</span> (Student) ioc.getBean(<span class="string">&quot;studentOne&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h4 id="3-2-2-方式二：通过类型（类的Class对象）">3.2.2 方式二：通过类型（类的Class对象）</h4>
<p>注意：<strong>要求ioc容器中有且仅有一个与之匹配的bean</strong><br>
若没有任何一个类型匹配的bean，抛出NoSuchBeanDefinitionException<br>
若有多个类型匹配的bean，抛出NoUniqueBeanDefinitionException</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Test</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">testIOC</span><span class="params">()</span>&#123;</span><br><span class="line">        <span class="type">ApplicationContext</span> <span class="variable">ioc</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ClassPathXmlApplicationContext</span>(<span class="string">&quot;spring-ioc.xml&quot;</span>);</span><br><span class="line">     <span class="comment">//获取bean</span></span><br><span class="line"><span class="comment">//        2.通过类的Class对象获取</span></span><br><span class="line">        <span class="type">Student</span> <span class="variable">studentOne</span> <span class="operator">=</span> ioc.getBean(Student.class);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h4 id="3-2-3-方式三：通过类型和id">3.2.3 方式三：通过类型和id</h4>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Test</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">testIOC</span><span class="params">()</span>&#123;</span><br><span class="line">        <span class="type">ApplicationContext</span> <span class="variable">ioc</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ClassPathXmlApplicationContext</span>(<span class="string">&quot;spring-ioc.xml&quot;</span>);</span><br><span class="line"></span><br><span class="line">    <span class="comment">//3.通过类型和id获取</span></span><br><span class="line">    <span class="type">Student</span> <span class="variable">studentOne</span> <span class="operator">=</span> ioc.getBean(<span class="string">&quot;studentOne&quot;</span>,Student.class);</span><br><span class="line">    System.out.println(studentOne);</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h4 id="3-2-4-获取bean的方式总结">3.2.4 获取bean的方式总结</h4>
<p>以后用的最多的就是第二种方式，一个类型的bean只需要配置一次就可以了，如果真的需要多个实例，那么配置时加上scope属性选择多例就可以了</p>
<p>注意：<strong>在IOC容器中通过工厂模式和反射技术创建对象，所以需要对象的无参构造器</strong></p>
<h4 id="3-2-5-对于接口">3.2.5 对于接口</h4>
<p>xml文件中不能写接口，很简单，接口没有实例对象，也没有无参构造器<br>
如果组件类实现了接口，根据接口类型可以获取 bean 吗？</p>
<p>可以，前提是bean唯一</p>
<p>如果一个接口有多个实现类，这些实现类都配置了 bean，根据接口类型可以获取 bean 吗？</p>
<p>不行，因为bean不唯一</p>
<p>下面这个会得到接口的实现类对象</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Test</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">testIOC</span><span class="params">()</span>&#123;</span><br><span class="line">    <span class="type">ApplicationContext</span> <span class="variable">ioc</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ClassPathXmlApplicationContext</span>(<span class="string">&quot;spring-ioc.xml&quot;</span>);</span><br><span class="line"></span><br><span class="line">    <span class="comment">//通过接口获取实例</span></span><br><span class="line">    <span class="type">Person</span> <span class="variable">person</span> <span class="operator">=</span> ioc.getBean(Person.class);</span><br><span class="line">    System.out.println(person);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h4 id="3-2-6-根据类型获取bean的实质">3.2.6 根据类型获取bean的实质</h4>
<p>根据类型来获取bean时，在满足bean唯一性的前提下，其实只是看：</p>
<p><code>对象 instanceof 指定的类型 </code>的返回结果，只要返回的是true就可以认定为和类型匹配，能够获取到。</p>
<p>即通过bean的类型、bean所继承的类的类型、bean所实现的接口的类型都可以获取bean</p>
<h3 id="3-3-依赖注入">3.3 依赖注入</h3>
<h4 id="setter注入和构造器注入⭐">setter注入和构造器注入⭐</h4>
<p>分别是调用类的set方法和有参构造</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!--主要属性和成员变量的区别--&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;studentTwo&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.zylai.spring.pojo.Student&quot;</span>&gt;</span></span><br><span class="line">    <span class="comment">&lt;!--</span></span><br><span class="line"><span class="comment">        property：通过成员变量的set方法进行赋值</span></span><br><span class="line"><span class="comment">        name：设置需要赋值的属性名（和set方法有关，set方法名，去掉set之后首字母大写）</span></span><br><span class="line"><span class="comment">        value：设置属性的值</span></span><br><span class="line"><span class="comment">    --&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;sid&quot;</span> <span class="attr">value</span>=<span class="string">&quot;1001&quot;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;sname&quot;</span> <span class="attr">value</span>=<span class="string">&quot;张三&quot;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;age&quot;</span> <span class="attr">value</span>=<span class="string">&quot;23&quot;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;gender&quot;</span> <span class="attr">value</span>=<span class="string">&quot;男&quot;</span>/&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;studentThree&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.zylai.spring.pojo.Student&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">constructor-arg</span> <span class="attr">value</span>=<span class="string">&quot;1002&quot;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">constructor-arg</span> <span class="attr">value</span>=<span class="string">&quot;李四&quot;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">constructor-arg</span> <span class="attr">value</span>=<span class="string">&quot;女&quot;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">constructor-arg</span> <span class="attr">value</span>=<span class="string">&quot;23&quot;</span> <span class="attr">name</span>=<span class="string">&quot;age&quot;</span>/&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br></pre></td></tr></table></figure>
<h4 id="3-3-1-特殊值处理">3.3.1 特殊值处理</h4>
<p>特殊字符和CDATA节的处理如下：</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!--特殊值处理--&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;studentFour&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.zylai.spring.pojo.Student&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;sid&quot;</span> <span class="attr">value</span>=<span class="string">&quot;1003&quot;</span>/&gt;</span></span><br><span class="line">    <span class="comment">&lt;!--</span></span><br><span class="line"><span class="comment">        对于特殊字符，应该使用该特殊字符对应的实体</span></span><br><span class="line"><span class="comment">        &lt;  &amp;lt;</span></span><br><span class="line"><span class="comment">        &gt;  &amp;gt;</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">        另外也可以使用CDATA节其中的内容会原样解析,</span></span><br><span class="line"><span class="comment">        CDATA节是xml中一个特殊的标签，不能写在属性中，只能通过一个标签写入</span></span><br><span class="line"><span class="comment">    --&gt;</span></span><br><span class="line">    <span class="comment">&lt;!--&lt;property name=&quot;sname&quot; value=&quot;&amp;lt;王五&amp;gt;&quot;/&gt;--&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;sname&quot;</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">value</span>&gt;</span>&lt;![CDATA[&lt;王五&gt;]]&gt;<span class="tag">&lt;/<span class="name">value</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">property</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;gender&quot;</span>&gt;</span></span><br><span class="line">        <span class="comment">&lt;!--使性别这个属性为null--&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">null</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">property</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br></pre></td></tr></table></figure>
<h4 id="3-3-2-类类型的属性赋值">3.3.2 类类型的属性赋值</h4>
<p>三种方式：</p>
<p>ref：ref引用IOC容器中的某个bean的id</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;studentFive&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.zylai.spring.pojo.Student&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;sid&quot;</span> <span class="attr">value</span>=<span class="string">&quot;1006&quot;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;sname&quot;</span> <span class="attr">value</span>=<span class="string">&quot;张六&quot;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;age&quot;</span> <span class="attr">value</span>=<span class="string">&quot;23&quot;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;gender&quot;</span> <span class="attr">value</span>=<span class="string">&quot;男&quot;</span>/&gt;</span></span><br><span class="line">    </span><br><span class="line">    <span class="comment">&lt;!--ref引用IOC容器中的某个bean的id--&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;clazz&quot;</span> <span class="attr">ref</span>=<span class="string">&quot;clazzOne&quot;</span>/&gt;</span></span><br><span class="line">   </span><br><span class="line"><span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>级联：级联的方式，要求clazz属性赋值或者实例化。所以一般不用</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;studentFive&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.zylai.spring.pojo.Student&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;sid&quot;</span> <span class="attr">value</span>=<span class="string">&quot;1006&quot;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;sname&quot;</span> <span class="attr">value</span>=<span class="string">&quot;张六&quot;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;age&quot;</span> <span class="attr">value</span>=<span class="string">&quot;23&quot;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;gender&quot;</span> <span class="attr">value</span>=<span class="string">&quot;男&quot;</span>/&gt;</span></span><br><span class="line">   </span><br><span class="line">    <span class="comment">&lt;!--级联的方式，要求clazz属性赋值或者实例化。所以一般不用--&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;clazz.cid&quot;</span> <span class="attr">value</span>=<span class="string">&quot;1122&quot;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;clazz.cname&quot;</span> <span class="attr">value</span>=<span class="string">&quot;哈哈班&quot;</span>/&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>内部bean：在属性中设置一个bean。</p>
<blockquote>
<p>注意：不能通过ioc容器获取，相当于内部类，只能在当前student内使用</p>
</blockquote>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;studentFive&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.zylai.spring.pojo.Student&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;sid&quot;</span> <span class="attr">value</span>=<span class="string">&quot;1006&quot;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;sname&quot;</span> <span class="attr">value</span>=<span class="string">&quot;张六&quot;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;age&quot;</span> <span class="attr">value</span>=<span class="string">&quot;23&quot;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;gender&quot;</span> <span class="attr">value</span>=<span class="string">&quot;男&quot;</span>/&gt;</span></span><br><span class="line">    <span class="comment">&lt;!--内部bean，在属性中设置一个bean。</span></span><br><span class="line"><span class="comment">    注意：不能通过ioc容器获取，相当于内部类，只能在当前student内使用--&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;clazz&quot;</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;clazzInner&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.zylai.spring.pojo.Clazz&quot;</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;cid&quot;</span> <span class="attr">value</span>=<span class="string">&quot;1122&quot;</span>/&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;cname&quot;</span> <span class="attr">value</span>=<span class="string">&quot;王班&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">property</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br></pre></td></tr></table></figure>
<h4 id="3-3-3-数组">3.3.3 数组</h4>
<p>在属性中使用<code>array</code>标签，标签中数组元素的值写在<code>value</code>中</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!--数组--&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;studentSix&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.zylai.spring.pojo.Student&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;sid&quot;</span> <span class="attr">value</span>=<span class="string">&quot;1006&quot;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;sname&quot;</span> <span class="attr">value</span>=<span class="string">&quot;张六&quot;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;age&quot;</span> <span class="attr">value</span>=<span class="string">&quot;23&quot;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;gender&quot;</span> <span class="attr">value</span>=<span class="string">&quot;男&quot;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;clazz&quot;</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;clazzInner&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.zylai.spring.pojo.Clazz&quot;</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;cid&quot;</span> <span class="attr">value</span>=<span class="string">&quot;1122&quot;</span>/&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;cname&quot;</span> <span class="attr">value</span>=<span class="string">&quot;王班&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">property</span>&gt;</span></span><br><span class="line">    </span><br><span class="line">    <span class="comment">&lt;!--数组属性--&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;hobbies&quot;</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">array</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">value</span>&gt;</span>唱<span class="tag">&lt;/<span class="name">value</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">value</span>&gt;</span>跳<span class="tag">&lt;/<span class="name">value</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">value</span>&gt;</span>rap<span class="tag">&lt;/<span class="name">value</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">array</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">property</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br></pre></td></tr></table></figure>
<h4 id="3-3-4-list集合">3.3.4 list集合</h4>
<p>方式一：在属性中使用list标签</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!--</span></span><br><span class="line"><span class="comment">    list集合</span></span><br><span class="line"><span class="comment">    1.在属性中使用list标签</span></span><br><span class="line"><span class="comment">    2.再写一个集合类型的bean</span></span><br><span class="line"><span class="comment">--&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;clazzTwo&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.zylai.spring.pojo.Clazz&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;cid&quot;</span> <span class="attr">value</span>=<span class="string">&quot;1111&quot;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;cname&quot;</span> <span class="attr">value</span>=<span class="string">&quot;王者班&quot;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;studentList&quot;</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">list</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">ref</span> <span class="attr">bean</span>=<span class="string">&quot;studentOne&quot;</span>/&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">ref</span> <span class="attr">bean</span>=<span class="string">&quot;studentTwo&quot;</span>/&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">ref</span> <span class="attr">bean</span>=<span class="string">&quot;studentThree&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">list</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">property</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>方式二：再写一个集合类型的bean</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!--</span></span><br><span class="line"><span class="comment">    list集合</span></span><br><span class="line"><span class="comment">    1.在属性中使用list标签</span></span><br><span class="line"><span class="comment">    2.再写一个集合类型的bean</span></span><br><span class="line"><span class="comment">--&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;clazzTwo&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.zylai.spring.pojo.Clazz&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;cid&quot;</span> <span class="attr">value</span>=<span class="string">&quot;1111&quot;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;cname&quot;</span> <span class="attr">value</span>=<span class="string">&quot;王者班&quot;</span>/&gt;</span></span><br><span class="line">    </span><br><span class="line">    <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;studentList&quot;</span> <span class="attr">ref</span>=<span class="string">&quot;studentList&quot;</span>/&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">&lt;!--配置一个集合类型的bean，需要使用util的约束--&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">util:list</span> <span class="attr">id</span>=<span class="string">&quot;studentList&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">ref</span> <span class="attr">bean</span>=<span class="string">&quot;studentFour&quot;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">ref</span> <span class="attr">bean</span>=<span class="string">&quot;studentFive&quot;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">ref</span> <span class="attr">bean</span>=<span class="string">&quot;studentSix&quot;</span>/&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">util:list</span>&gt;</span></span><br></pre></td></tr></table></figure>
<h4 id="3-3-5-map集合">3.3.5 map集合</h4>
<p>方式和list差不多</p>
<p>方式一：设置map标签</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;studentSix&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.zylai.spring.pojo.Student&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;sid&quot;</span> <span class="attr">value</span>=<span class="string">&quot;1006&quot;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;sname&quot;</span> <span class="attr">value</span>=<span class="string">&quot;张六&quot;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;age&quot;</span> <span class="attr">value</span>=<span class="string">&quot;23&quot;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;gender&quot;</span> <span class="attr">value</span>=<span class="string">&quot;男&quot;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;clazz&quot;</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;clazzInner&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.zylai.spring.pojo.Clazz&quot;</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;cid&quot;</span> <span class="attr">value</span>=<span class="string">&quot;1122&quot;</span>/&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;cname&quot;</span> <span class="attr">value</span>=<span class="string">&quot;王班&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">property</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;hobbies&quot;</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">array</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">value</span>&gt;</span>唱<span class="tag">&lt;/<span class="name">value</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">value</span>&gt;</span>跳<span class="tag">&lt;/<span class="name">value</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">value</span>&gt;</span>rap<span class="tag">&lt;/<span class="name">value</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">array</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">property</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">&lt;!--map集合，和list差不多，就是需要设置键值对。第二种方式就是util了--&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;teacherMap&quot;</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">map</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">entry</span> <span class="attr">key</span>=<span class="string">&quot;语文老师&quot;</span> <span class="attr">value-ref</span>=<span class="string">&quot;teacherOne&quot;</span>/&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">entry</span> <span class="attr">key</span>=<span class="string">&quot;数学老师&quot;</span> <span class="attr">value-ref</span>=<span class="string">&quot;teacherTwo&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">map</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">property</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>方式二：写一个集合类型的bean</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;studentSix&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.zylai.spring.pojo.Student&quot;</span>&gt;</span></span><br><span class="line">   ···略</span><br><span class="line">    <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;teacherMap&quot;</span> <span class="attr">ref</span>=<span class="string">&quot;teacherMap&quot;</span>/&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">util:map</span> <span class="attr">id</span>=<span class="string">&quot;teacherMap&quot;</span>&gt;</span></span><br><span class="line">   <span class="tag">&lt;<span class="name">entry</span> <span class="attr">key</span>=<span class="string">&quot;语文老师&quot;</span> <span class="attr">value-ref</span>=<span class="string">&quot;teacherOne&quot;</span>/&gt;</span></span><br><span class="line">   <span class="tag">&lt;<span class="name">entry</span> <span class="attr">key</span>=<span class="string">&quot;数学老师&quot;</span> <span class="attr">value-ref</span>=<span class="string">&quot;teacherTwo&quot;</span>/&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">util:map</span>&gt;</span></span><br></pre></td></tr></table></figure>
<h4 id="3-3-6-p命名空间">3.3.6 p命名空间</h4>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!--p命名空间，需要在xml文件最开始设置引入--&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;studentSeven&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.zylai.spring.pojo.Student&quot;</span></span></span><br><span class="line"><span class="tag">      <span class="attr">p:sid</span>=<span class="string">&quot;1008&quot;</span> <span class="attr">p:sname</span>=<span class="string">&quot;小红&quot;</span> <span class="attr">p:clazz-ref</span>=<span class="string">&quot;clazzOne&quot;</span></span></span><br><span class="line"><span class="tag">      <span class="attr">p:teacherMap-ref</span>=<span class="string">&quot;teacherMap&quot;</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br></pre></td></tr></table></figure>
<h3 id="3-4-管理数据源和外部文件">3.4  管理数据源和外部文件</h3>
<h4 id="加入依赖">加入依赖</h4>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!-- MySQL驱动 --&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>mysql<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>mysql-connector-java<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">version</span>&gt;</span>8.0.16<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"><span class="comment">&lt;!-- 数据源 --&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>com.alibaba<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>druid<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">version</span>&gt;</span>1.0.31<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>
<h4 id="创建jdbc的配置文件">创建jdbc的配置文件</h4>
<p><code>jdbc.propertiesjdbc.properties</code></p>
<figure class="highlight properties"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">jdbc.driver</span>=<span class="string">com.mysql.cj.jdbc.Driver</span></span><br><span class="line"><span class="attr">jdbc.url</span>=<span class="string">jdbc:mysql://localhost:3306/ssm?serverTimezone=UTC</span></span><br><span class="line"><span class="attr">jdbc.username</span>=<span class="string">root</span></span><br><span class="line"><span class="attr">jdbc.password</span>=<span class="string">root</span></span><br><span class="line"><span class="attr">initialSize</span>=<span class="string">5</span></span><br><span class="line"><span class="attr">maxActive</span>=<span class="string">9</span></span><br></pre></td></tr></table></figure>
<h4 id="配置DataSource">配置DataSource</h4>
<blockquote>
<p>注意：需要通过context标签引入外部文件，注意context标签在xml文件头对应的链接</p>
</blockquote>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?xml version=<span class="string">&quot;1.0&quot;</span> encoding=<span class="string">&quot;UTF-8&quot;</span>?&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">beans</span> <span class="attr">xmlns</span>=<span class="string">&quot;http://www.springframework.org/schema/beans&quot;</span></span></span><br><span class="line"><span class="tag">       <span class="attr">xmlns:xsi</span>=<span class="string">&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</span></span></span><br><span class="line"><span class="tag">       <span class="attr">xmlns:context</span>=<span class="string">&quot;http://www.springframework.org/schema/context&quot;</span></span></span><br><span class="line"><span class="tag">       <span class="attr">xsi:schemaLocation</span>=<span class="string">&quot;http://www.springframework.org/schema/beans</span></span></span><br><span class="line"><span class="string"><span class="tag">       http://www.springframework.org/schema/beans/spring-beans.xsd</span></span></span><br><span class="line"><span class="string"><span class="tag">       http://www.springframework.org/schema/context</span></span></span><br><span class="line"><span class="string"><span class="tag">        http://www.springframework.org/schema/context/spring-context-4.2.xsd&quot;</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">&lt;!--引入jdbc.properties，之后可以通过$&#123;key&#125;的方式访问value--&gt;</span></span><br><span class="line">    <span class="comment">&lt;!--这里的context标签，注意上面引入的--&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">context:property-placeholder</span> <span class="attr">location</span>=<span class="string">&quot;jdbc.properties&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">context:property-placeholder</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;datasource&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.alibaba.druid.pool.DruidDataSource&quot;</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;driverClassName&quot;</span> <span class="attr">value</span>=<span class="string">&quot;$&#123;jdbc.driver&#125;&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;url&quot;</span> <span class="attr">value</span>=<span class="string">&quot;$&#123;jdbc.url&#125;&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;username&quot;</span> <span class="attr">value</span>=<span class="string">&quot;$&#123;jdbc.username&#125;&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;password&quot;</span> <span class="attr">value</span>=<span class="string">&quot;$&#123;jdbc.password&#125;&quot;</span>/&gt;</span></span><br><span class="line">        <span class="comment">&lt;!--&lt;property name=&quot;initialSize&quot; value=&quot;$&#123;initialSize&#125;&quot;/&gt;--&gt;</span></span><br><span class="line">        <span class="comment">&lt;!--&lt;property name=&quot;maxActive&quot; value=&quot;$&#123;maxActive&#125;&quot;/&gt;--&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">beans</span>&gt;</span></span><br></pre></td></tr></table></figure>
<h3 id="3-5-bean的作用域">3.5 bean的作用域</h3>
<p><img src="https://zylai-cloud-pic-1306915061.cos.ap-nanjing.myqcloud.com/images01/Spring.assets/image-20220803165429301.png" alt="image-20220803165429301"></p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!--</span></span><br><span class="line"><span class="comment">    scope默认是单例，可以选择prototype多例</span></span><br><span class="line"><span class="comment">    scope=&quot;singleton|prototype&quot;</span></span><br><span class="line"><span class="comment">    singleton:单例，表示获取该bean所对应的对象都是同一个</span></span><br><span class="line"><span class="comment">    prototype:多例，表示获取该bean所对应的对象都不是同一个</span></span><br><span class="line"><span class="comment">--&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;student&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.zylai.spring.pojo.Student&quot;</span> <span class="attr">scope</span>=<span class="string">&quot;prototype&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;sid&quot;</span> <span class="attr">value</span>=<span class="string">&quot;1001&quot;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;sname&quot;</span> <span class="attr">value</span>=<span class="string">&quot;张三&quot;</span>/&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br></pre></td></tr></table></figure>
<h3 id="3-6-bean的生命周期">3.6  bean的生命周期</h3>
<ol>
<li>实例化，调用无参构造</li>
<li>实例注入，调用set方法</li>
<li>初始化之前的操作（由后置处理器负责）</li>
<li>初始化，需要通过bean的init-method属性指定初始化方法</li>
<li>初始化之后的操作（由后置处理器负责）</li>
<li>IOC容器关闭时销毁</li>
</ol>
<p>测试验证：</p>
<p>实例：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">User</span> &#123;</span><br><span class="line">    <span class="keyword">private</span> Integer id;</span><br><span class="line">    <span class="keyword">private</span> String username;</span><br><span class="line">    <span class="keyword">private</span> String password;</span><br><span class="line">    <span class="keyword">private</span> Integer age;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">User</span><span class="params">()</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;生命周期：1、创建对象&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">User</span><span class="params">(Integer id, String username, String password, Integer age)</span> &#123;</span><br><span class="line">        <span class="built_in">this</span>.id = id;</span><br><span class="line">        <span class="built_in">this</span>.username = username;</span><br><span class="line">        <span class="built_in">this</span>.password = password;</span><br><span class="line">        <span class="built_in">this</span>.age = age;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> Integer <span class="title function_">getId</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> id;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">setId</span><span class="params">(Integer id)</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;生命周期：2、依赖注入&quot;</span>);</span><br><span class="line">        <span class="built_in">this</span>.id = id;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">getUsername</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> username;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">setUsername</span><span class="params">(String username)</span> &#123;</span><br><span class="line">        <span class="built_in">this</span>.username = username;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">getPassword</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> password;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">setPassword</span><span class="params">(String password)</span> &#123;</span><br><span class="line">        <span class="built_in">this</span>.password = password;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> Integer <span class="title function_">getAge</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> age;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">setAge</span><span class="params">(Integer age)</span> &#123;</span><br><span class="line">        <span class="built_in">this</span>.age = age;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">initMethod</span><span class="params">()</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;生命周期：3、初始化&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">destroyMethod</span><span class="params">()</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;生命周期：4、销毁&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">toString</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;User&#123;&quot;</span> +</span><br><span class="line">                <span class="string">&quot;id=&quot;</span> + id +</span><br><span class="line">                <span class="string">&quot;, username=&#x27;&quot;</span> + username + <span class="string">&#x27;\&#x27;&#x27;</span> +</span><br><span class="line">                <span class="string">&quot;, password=&#x27;&quot;</span> + password + <span class="string">&#x27;\&#x27;&#x27;</span> +</span><br><span class="line">                <span class="string">&quot;, age=&quot;</span> + age +</span><br><span class="line">                <span class="string">&#x27;&#125;&#x27;</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>后置处理：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">MyBeanPostProcessor</span> <span class="keyword">implements</span> <span class="title class_">BeanPostProcessor</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> Object <span class="title function_">postProcessBeforeInitialization</span><span class="params">(Object bean, String beanName)</span> <span class="keyword">throws</span> BeansException &#123;</span><br><span class="line">        <span class="comment">//此方法在bean的生命周期初始化之前执行</span></span><br><span class="line">        System.out.println(<span class="string">&quot;MyBeanPostProcessor--&gt;后置处理postProcessBeforeInitialization&quot;</span>);</span><br><span class="line">        <span class="keyword">return</span> bean;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> Object <span class="title function_">postProcessAfterInitialization</span><span class="params">(Object bean, String beanName)</span> <span class="keyword">throws</span> BeansException &#123;</span><br><span class="line">        <span class="comment">//此方法在bean的生命周期初始化之后执行</span></span><br><span class="line">        System.out.println(<span class="string">&quot;MyBeanPostProcessor--&gt;后置处理postProcessAfterInitialization&quot;</span>);</span><br><span class="line">        <span class="keyword">return</span> bean;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>测试方法：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 1、实例化，调用无参构造</span></span><br><span class="line"><span class="comment"> * 2、实例注入，调用set</span></span><br><span class="line"><span class="comment"> * 3、后置处理的postProcessBeforeInitialization方法</span></span><br><span class="line"><span class="comment"> * 4、初始化，需要通过bean的init-method属性指定初始化方法</span></span><br><span class="line"><span class="comment"> *    使用bean</span></span><br><span class="line"><span class="comment"> * 5、后置处理的postProcessAfterInitialization方法</span></span><br><span class="line"><span class="comment"> * 6、IOC容器关闭时销毁，需要使用bean的destroy-method属性指定销毁方法</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * bean的作用域是单例时，在创建IOC容器时，bean实例就会被创建</span></span><br><span class="line"><span class="comment"> * 作用域是多例时，只有在获取bean实例时才会被创建</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * bean的后置处理器会在生命周期的初始化前后添加额外的操作，</span></span><br><span class="line"><span class="comment"> * 需要实现BeanPostProcessor接口，</span></span><br><span class="line"><span class="comment"> * 且配置到IOC容器中，需要注意的是，bean后置处理器不是单独针对某一个bean生效，</span></span><br><span class="line"><span class="comment"> * 而是针对IOC容器中所有bean都会执行</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@Test</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">test</span><span class="params">()</span>&#123;</span><br><span class="line">    <span class="comment">//ClassPathXmlApplicationContext扩展了刷新和销毁的子方法</span></span><br><span class="line">    <span class="type">ClassPathXmlApplicationContext</span> <span class="variable">ioc</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ClassPathXmlApplicationContext</span>(<span class="string">&quot;spring-lifecycle.xml&quot;</span>);</span><br><span class="line">    <span class="type">User</span> <span class="variable">user</span> <span class="operator">=</span> ioc.getBean(User.class);</span><br><span class="line">    System.out.println(<span class="string">&quot;获取bean并使用：&quot;</span>+user);</span><br><span class="line">    ioc.close();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>结果：</p>
<p><img src="https://zylai-cloud-pic-1306915061.cos.ap-nanjing.myqcloud.com/images01/Spring.assets/image-20220803165753224.png" alt="image-20220803165753224"></p>
<h3 id="3-7-工厂bean">3.7  工厂bean</h3>
<h4 id="概念">概念</h4>
<p>FactoryBean是Spring提供的一种整合第三方框架的常用机制。</p>
<p>和普通的bean不同，配置一个FactoryBean类型的bean，在获取bean的时候得到的并不是class属性中配置的这个类的对象，而是getObject()方法的返回值。</p>
<p>通过这种机制，Spring可以帮我们把复杂组件创建的详细过程和繁琐细节都屏蔽起来，只把最简洁的使用界面展示给我们。</p>
<p>将来我们整合Mybatis时，Spring就是通过FactoryBean机制来帮我们创建SqlSessionFactory对象的。</p>
<blockquote>
<p>一句话：IOC容器会创建工厂bean <code>getObject</code>方法返回的实例类型，不会去创建工厂bean的实例。这样我们直接从ioc容器中获取工厂创建的实例对象</p>
</blockquote>
<h4 id="实现FactoryBean接口">实现FactoryBean接口</h4>
<p>接口中的三个方法：</p>
<ul>
<li>getObject():返回一个对象给IOC容器</li>
<li>getObjectType():设置所提供对象的类型</li>
<li>isSingleton():所提供的对象是否为单例</li>
</ul>
<p>当把FactoryBean的实现类配置为bean时，会将当前类中的getObject方法返回的对象交给IOC容器管理</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">UserFactoryBean</span> <span class="keyword">implements</span> <span class="title class_">FactoryBean</span>&lt;User&gt; &#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> User <span class="title function_">getObject</span><span class="params">()</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">User</span>();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> Class&lt;?&gt; getObjectType() &#123;</span><br><span class="line">        <span class="keyword">return</span> User.class;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">FactoryTest</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Test</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">test</span><span class="params">()</span>&#123;</span><br><span class="line"><span class="comment">//         在配置文件中只需要配置FactoryBean即可</span></span><br><span class="line"><span class="comment">//        当把FactoryBean的实现类配置为bean时，</span></span><br><span class="line"><span class="comment">//        真正交给IOC容器管理的对象，是FactoryBean工厂中getObject方法返回的对象</span></span><br><span class="line"><span class="comment">//        也就是说，省略了传统的工厂模式从工厂实例中获取产品的步骤，</span></span><br><span class="line"><span class="comment">//        而是直接把工厂的产品交给了ioc容器管理</span></span><br><span class="line"><span class="comment">//        另外，还可以设置是否为单例</span></span><br><span class="line">        <span class="type">ApplicationContext</span> <span class="variable">ioc</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ClassPathXmlApplicationContext</span>(<span class="string">&quot;spring-factory.xml&quot;</span>);</span><br><span class="line">        <span class="type">User</span> <span class="variable">user</span> <span class="operator">=</span> ioc.getBean(User.class);</span><br><span class="line">        System.out.println(user);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="3-8-自动装配⭐">3.8  自动装配⭐</h3>
<h4 id="概念-v2">概念</h4>
<p>根据指定的策略，在IOC容器中匹配某个bean，自动为为bean中的类类型的属性或者接口类型的属性赋值</p>
<h4 id="实现">实现</h4>
<p>可以通过bean标签的autowire属性设置自动装配的策略</p>
<p>自动装配的策略：</p>
<ol>
<li>
<p>no,default：表示不装配，即bean中的属性不会自动匹配某个bean为某个属性赋值</p>
</li>
<li>
<p>byType：根据赋值的属性的类型，在IOC容器中匹配某个bean为属性赋值</p>
<p>异常情况：</p>
<ul>
<li>IOC中一个类型都匹配不上：属性就不会装配，使用默认值</li>
<li>有多个类型的bean，此时会抛出异常</li>
<li>总结：当使用ByType实现自动装配时，IOC容器中有且仅有一个类型匹配的bean能够为属性赋值</li>
</ul>
</li>
<li>
<p>byName：将要赋值的属性的属性名作为bean的id在IOC容器中匹配某个bean，为属性赋值</p>
</li>
<li>
<p>总结：一般使用byType。特殊情况下：当类型匹配的bean有多个时，此时可以使用byName实现自动装配</p>
</li>
</ol>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?xml version=<span class="string">&quot;1.0&quot;</span> encoding=<span class="string">&quot;UTF-8&quot;</span>?&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">beans</span> <span class="attr">xmlns</span>=<span class="string">&quot;http://www.springframework.org/schema/beans&quot;</span></span></span><br><span class="line"><span class="tag">       <span class="attr">xmlns:xsi</span>=<span class="string">&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</span></span></span><br><span class="line"><span class="tag">       <span class="attr">xsi:schemaLocation</span>=<span class="string">&quot;http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd&quot;</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="name">bean</span> <span class="attr">class</span>=<span class="string">&quot;com.zylai.spring.controller.UserController&quot;</span></span></span><br><span class="line"><span class="tag">          <span class="attr">autowire</span>=<span class="string">&quot;byType&quot;</span>&gt;</span></span><br><span class="line">        <span class="comment">&lt;!--&lt;property name=&quot;userService&quot; ref=&quot;userService&quot;/&gt;--&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;userService&quot;</span></span></span><br><span class="line"><span class="tag">          <span class="attr">class</span>=<span class="string">&quot;com.zylai.spring.service.impl.UserServiceImpl&quot;</span></span></span><br><span class="line"><span class="tag">          <span class="attr">autowire</span>=<span class="string">&quot;byType&quot;</span>&gt;</span></span><br><span class="line">        <span class="comment">&lt;!--&lt;property name=&quot;userDao&quot; ref=&quot;userDao&quot;/&gt;--&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;userDao&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.zylai.spring.dao.impl.UserDaoImpl&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">beans</span>&gt;</span></span><br></pre></td></tr></table></figure>
<h2 id="4-IOC-基于注解管理Bean">4 IOC-基于注解管理Bean</h2>
<h3 id="4-1-使用注解注册bean组件">4.1 使用注解注册bean组件</h3>
<ol>
<li>@Component：将类标识为普通组件</li>
<li>@Controller：将类标识为控制层组件</li>
<li>@Service：将类标识为业务层组件</li>
<li>@Repository：将类标识为持久层组件</li>
</ol>
<p>这四个注解本质和功能上完全一样，后面三个相当于Component改了个名字，但是对于开发人员便于理解</p>
<p>注意：</p>
<ul>
<li>
<p>在service层和dao层，注解应该标识在接口的实现类上</p>
</li>
<li>
<p>加了注解的类在IOC容器中的<strong>默认id为类名的小驼峰</strong></p>
</li>
</ul>
<h3 id="4-2-扫描组件">4.2  扫描组件</h3>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line">    <span class="comment">&lt;!--开启组件扫描--&gt;</span></span><br><span class="line"><span class="comment">&lt;!--    &lt;contxt:component-scan base-package=&quot;com.zylai.spring.controller,com.zylai.spring.service.impl,--&gt;</span></span><br><span class="line"><span class="comment">&lt;!--com.zylai.spring.dao.impl&quot;/&gt;--&gt;</span></span><br><span class="line"><span class="comment">&lt;!--    这个包下面下的所有类都会扫描--&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">contxt:component-scan</span> <span class="attr">base-package</span>=<span class="string">&quot;com.zylai.spring&quot;</span>&gt;</span></span><br><span class="line">        <span class="comment">&lt;!--contxt:exclude-filter 排除扫描，设置不扫描哪些</span></span><br><span class="line"><span class="comment">            annotation：根据注解类型进行排除，expression中设置排除的注解的全类名</span></span><br><span class="line"><span class="comment">            assignable：根据类名进行排除，expression中设置排除的类的全类名</span></span><br><span class="line"><span class="comment">            --&gt;</span></span><br><span class="line">        <span class="comment">&lt;!--&lt;contxt:exclude-filter type=&quot;annotation&quot; expression=&quot;org.springframework.stereotype.Controller&quot;/&gt;--&gt;</span></span><br><span class="line">        <span class="comment">&lt;!--&lt;contxt:exclude-filter type=&quot;assignable&quot; expression=&quot;com.zylai.spring.controller.UserController&quot;/&gt;--&gt;</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">&lt;!--contxt:include-filter 包含扫描，设置只扫描谁</span></span><br><span class="line"><span class="comment">            注意：需要在contxt:component-scan标签中设置属性use-default-filters=&quot;false&quot;,</span></span><br><span class="line"><span class="comment">            为false时，设置的包下面所有的类都不需要扫描，此时可以使用包含扫描</span></span><br><span class="line"><span class="comment">            为true时（默认的），设置的包下面所有的类都进行扫描，此时可以使用排除扫描</span></span><br><span class="line"><span class="comment">            --&gt;</span></span><br><span class="line">        <span class="comment">&lt;!--&lt;contxt:include-filter type=&quot;assignable&quot; expression=&quot;org.springframework.stereotype.Service&quot;/&gt;--&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">contxt:component-scan</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>通过注解加扫描所配置的bean的id，默认值为类名的小驼峰，即类名的首字母为小写的结果，注意，接口应该是其实现类。可以通过标识组件注解的value属性设置bean的自定义的id</p>
<h3 id="4-3-Autowired自动装配">4.3 @Autowired自动装配</h3>
<h4 id="4-3-1-能够标识的位置">4.3.1 能够标识的位置</h4>
<ul>
<li>成员变量上，此时不需要设置成员变量的set方法</li>
<li>set方法上</li>
<li>为当前成员变量赋值的有参构造器上</li>
</ul>
<h4 id="4-3-2-注入的方式">4.3.2 注入的方式</h4>
<p>@Autowired默认通过byType方式自动注入，在IOC容器中通过类型匹配某个bean为属性赋值</p>
<p>若有多个类型匹配的bean，此时会<strong>自动转化</strong>为byName的方式来实现自动装配的效果</p>
<p>即将要赋值的属性的属性名作为bean的id匹配某个bean为属性赋值</p>
<p>若byType和byName的方式都无法实现自动装配，即IOC容器中有多个类型匹配的bean，且这些bean的id和要复制的属性的属性名都不一致，此时抛异常。</p>
<p>此时可以在要赋值的属性上，添加一个注解<code>@Qualifier(&quot;value&quot;)</code>通过该注解的value属性值，指定某个bean的id，然后将这个bean为属性赋值</p>
<blockquote>
<p>注意：若IOC容器中没有任何一个类型匹配bean，此时抛出异常：NoSuchBeanDefinitionException</p>
<p>在@Autowired注解中有个required属性，默认值为true，要求必须完成自动装配</p>
<p>可以将required设置为false，此时能装配则装配，无法装配则使用属性的默认值</p>
</blockquote>
<h3 id="4-4-例子">4.4 例子</h3>
<p>controller：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Controller</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">UserController</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Autowired</span></span><br><span class="line">    <span class="keyword">private</span> UserService userService;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">saveUser</span><span class="params">()</span>&#123;</span><br><span class="line">        userService.saveUser();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>service</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Service</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">UserServiceImpl</span> <span class="keyword">implements</span> <span class="title class_">UserService</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Autowired</span></span><br><span class="line">    <span class="keyword">private</span> UserDao userDao;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">saveUser</span><span class="params">()</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;保存信息--&gt;service&quot;</span>);</span><br><span class="line">        userDao.saveUser();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>dao</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Repository</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">UserDaoImpl</span> <span class="keyword">implements</span> <span class="title class_">UserDao</span> &#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">saveUser</span><span class="params">()</span> &#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;保存成功--&gt;dao&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p><img src="https://zylai-cloud-pic-1306915061.cos.ap-nanjing.myqcloud.com/images01/Spring.assets/image-20220803171641013.png" alt="image-20220803171641013"></p>
<h2 id="5-AOP-概念">5 AOP-概念</h2>
<h3 id="5-1-代理模式">5.1 代理模式</h3>
<h4 id="5-1-1-概念">5.1.1 概念</h4>
<p>二十三种设计模式中的一种，属于结构型模式。它的作用就是通过提供一个代理类，让我们在调用目标方法的时候，不再是直接对目标方法进行调用，而是通过代理类间接调用。</p>
<p>让不属于目标方法核心逻辑的代码从目标方法中剥离出来——解耦。调用目标方法时先调用代理对象的方法，减少对目标方法的调用和打扰，同时让附加功能能够集中在一起也有利于统一维护。</p>
<p><img src="https://zylai-cloud-pic-1306915061.cos.ap-nanjing.myqcloud.com/images01/Spring.assets/image-20220728115238117.png" alt="image-20220728115238117"></p>
<h4 id="5-1-2-静态代理">5.1.2 静态代理</h4>
<p>静态代理的思想就是代理对象和目标对象都实现同一个接口，然后在代理对象中调用目标对象的方法。</p>
<p>接口：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">interface</span> <span class="title class_">Calculator</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="type">int</span> <span class="title function_">add</span><span class="params">(<span class="type">int</span> i, <span class="type">int</span> j)</span>;</span><br><span class="line">    <span class="type">int</span> <span class="title function_">sub</span><span class="params">(<span class="type">int</span> i, <span class="type">int</span> j)</span>;</span><br><span class="line">    <span class="type">int</span> <span class="title function_">mul</span><span class="params">(<span class="type">int</span> i, <span class="type">int</span> j)</span>;</span><br><span class="line">    <span class="type">int</span> <span class="title function_">div</span><span class="params">(<span class="type">int</span> i, <span class="type">int</span> j)</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>目标对象：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">CalculatorImpl</span> <span class="keyword">implements</span> <span class="title class_">Calculator</span>&#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="type">int</span> <span class="title function_">add</span><span class="params">(<span class="type">int</span> i, <span class="type">int</span> j)</span> &#123;</span><br><span class="line">        <span class="type">int</span> <span class="variable">result</span> <span class="operator">=</span> i + j;</span><br><span class="line">        System.out.println(<span class="string">&quot;方法内部，result：&quot;</span>+result);</span><br><span class="line">        <span class="keyword">return</span> result;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="type">int</span> <span class="title function_">sub</span><span class="params">(<span class="type">int</span> i, <span class="type">int</span> j)</span> &#123;</span><br><span class="line">        <span class="type">int</span> <span class="variable">result</span> <span class="operator">=</span> i - j;</span><br><span class="line">        System.out.println(<span class="string">&quot;方法内部，result：&quot;</span>+result);</span><br><span class="line">        <span class="keyword">return</span> result;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="type">int</span> <span class="title function_">mul</span><span class="params">(<span class="type">int</span> i, <span class="type">int</span> j)</span> &#123;</span><br><span class="line">        <span class="type">int</span> <span class="variable">result</span> <span class="operator">=</span> i * j;</span><br><span class="line">        System.out.println(<span class="string">&quot;方法内部，result：&quot;</span>+result);</span><br><span class="line">        <span class="keyword">return</span> result;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="type">int</span> <span class="title function_">div</span><span class="params">(<span class="type">int</span> i, <span class="type">int</span> j)</span> &#123;</span><br><span class="line">        <span class="type">int</span> <span class="variable">result</span> <span class="operator">=</span> i / j;</span><br><span class="line">        System.out.println(<span class="string">&quot;方法内部，result：&quot;</span>+result);</span><br><span class="line">        <span class="keyword">return</span> result;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>代理对象：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">CalculatorStaticProxy</span> <span class="keyword">implements</span> <span class="title class_">Calculator</span> &#123;</span><br><span class="line"><span class="comment">// 将被代理的目标对象声明为成员变量</span></span><br><span class="line">    <span class="keyword">private</span> Calculator target;</span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">CalculatorStaticProxy</span><span class="params">(Calculator target)</span> &#123;</span><br><span class="line">    <span class="built_in">this</span>.target = target;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="type">int</span> <span class="title function_">add</span><span class="params">(<span class="type">int</span> i, <span class="type">int</span> j)</span> &#123;</span><br><span class="line">    <span class="comment">// 附加功能由代理类中的代理方法来实现</span></span><br><span class="line">    System.out.println(<span class="string">&quot;[日志] add 方法开始了，参数是：&quot;</span> + i + <span class="string">&quot;,&quot;</span> + j);</span><br><span class="line">    <span class="comment">// 通过目标对象来实现核心业务逻辑</span></span><br><span class="line">    <span class="type">int</span> <span class="variable">addResult</span> <span class="operator">=</span> target.add(i, j);</span><br><span class="line">    System.out.println(<span class="string">&quot;[日志] add 方法结束了，结果是：&quot;</span> + addResult);</span><br><span class="line">        <span class="keyword">return</span> addResult;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>可以看到，通过静态代理，达到了我们想要的目标。</p>
<p>缺点：代理都写死了，不具备灵活性。比如将来要给其他的类加上这个日志功能，那么还需要创建很多的代理类，产生大量重复的代码。</p>
<h4 id="5-1-3-动态代理">5.1.3 动态代理</h4>
<p>比如说，将日志功能都集中到一个代理类中，将来有任何的日志需求，都通过这一个代理类实现。这里就用到了动态代理的技术。</p>
<p>使用JDK动态代理：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">ProxyFactory</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> Object target;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">ProxyFactory</span><span class="params">(Object target)</span> &#123;</span><br><span class="line">        <span class="built_in">this</span>.target = target;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> Object <span class="title function_">getProxy</span><span class="params">()</span>&#123;</span><br><span class="line"></span><br><span class="line">        <span class="comment">//使用JDK动态代理</span></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * 必须给出类加载器，根据类加载器来创建类</span></span><br><span class="line"><span class="comment">         * ClassLoader loader：指定目标对象使用的类加载器</span></span><br><span class="line"><span class="comment">         * Class&lt;?&gt;[] interfaces：获取目标对象实现的所有接口的class对象的数组</span></span><br><span class="line"><span class="comment">         * InvocationHandler h ：设置代理类中的抽象方法如何重写</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="type">ClassLoader</span> <span class="variable">classLoader</span> <span class="operator">=</span> target.getClass().getClassLoader();</span><br><span class="line">        Class&lt;?&gt;[] interfaces = target.getClass().getInterfaces();</span><br><span class="line">        <span class="type">InvocationHandler</span> <span class="variable">h</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">InvocationHandler</span>() &#123;</span><br><span class="line"></span><br><span class="line">            <span class="comment">//这里是设置代理类中的方法如何重写</span></span><br><span class="line">            <span class="comment">//proxy:表示代理对象，method表示要执行的方法，args表示要执行的方法的参数列表</span></span><br><span class="line">            <span class="meta">@Override</span></span><br><span class="line">            <span class="keyword">public</span> Object <span class="title function_">invoke</span><span class="params">(Object proxy, Method method, Object[] args)</span> <span class="keyword">throws</span> Throwable &#123;</span><br><span class="line">                <span class="type">Object</span> <span class="variable">res</span> <span class="operator">=</span> <span class="literal">null</span>;</span><br><span class="line">                <span class="keyword">try</span> &#123;</span><br><span class="line">                    System.out.println(<span class="string">&quot;日志，方法：&quot;</span>+method.getName()+<span class="string">&quot;,参数：&quot;</span>+ Arrays.toString(args));</span><br><span class="line">                    <span class="comment">//调用目标对象的方法</span></span><br><span class="line">                    res = method.invoke(target, args);</span><br><span class="line">                    System.out.println(<span class="string">&quot;日志，方法：&quot;</span>+method.getName()+<span class="string">&quot;,结果：&quot;</span>+res);</span><br><span class="line">                    <span class="keyword">return</span> res;</span><br><span class="line">                &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">                    e.printStackTrace();</span><br><span class="line">                    System.out.println(<span class="string">&quot;日志，方法：&quot;</span>+method.getName()+<span class="string">&quot;,异常：&quot;</span>+e);</span><br><span class="line">                &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">                    System.out.println(<span class="string">&quot;日志，方法：&quot;</span>+method.getName()+<span class="string">&quot;,方法执行完毕&quot;</span>);</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="keyword">return</span> res;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;;</span><br><span class="line">        <span class="keyword">return</span> Proxy.newProxyInstance(classLoader,interfaces,h);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">ProxyFactory</span> <span class="variable">proxyFactory</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ProxyFactory</span>(<span class="keyword">new</span> <span class="title class_">CalculatorImpl</span>());</span><br><span class="line"><span class="type">Calculator</span> <span class="variable">proxy</span> <span class="operator">=</span> (Calculator)proxyFactory.getProxy();</span><br><span class="line">proxy.add(<span class="number">1</span>,<span class="number">2</span>);</span><br></pre></td></tr></table></figure>
<h3 id="5-2-AOP概念及相关术语">5.2 AOP概念及相关术语</h3>
<h4 id="AOP">AOP</h4>
<p>AOP（Aspect Oriented Programming）面向切面编程，是一种设计思想，是面向对象编程的一种补充和完善。它以通过预编译方式和运行期动态代理方式实现在不修改源代码的情况下给程序动态统一添加额外功能的一种技术</p>
<p>简单来说：就是把非核心业务抽取出来，给切面类管理。再把抽取出来的放到相应的位置。</p>
<h4 id="横切关注点">横切关注点</h4>
<p>从目标对象中抽取出来的非核心业务，比如之前代理模式中的日志功能，针对于计算器功能来说，日志就是非核心业务。</p>
<p>这个概念不是语法层面天然存在的，而是根据附加功能的逻辑上的需要：有十个附加功能，就有十个横切关注点。</p>
<p><img src="https://zylai-cloud-pic-1306915061.cos.ap-nanjing.myqcloud.com/images01/Spring.assets/image-20220728150235449.png" alt="image-20220728150235449"></p>
<h4 id="通知">通知</h4>
<p>非核心的业务再目标对象中叫做横切关注点，将横切关注点抽取出来封装到切面类中，他就是这个类中的一个方法叫做通知。</p>
<p>每一个横切关注点要做的事情都封装成一个方法，这样的方法就叫做通知方法。</p>
<ul>
<li>前置通知：在被代理的目标方法前执行</li>
<li>返回通知：在被代理的目标方法成功结束后执行（寿终正寝）</li>
<li>异常通知：在被代理的目标方法异常结束后执行（死于非命）</li>
<li>后置通知：在被代理的目标方法最终结束后执行（盖棺定论）</li>
<li>环绕通知：使用try…catch…finally结构围绕整个被代理的目标方法，包括上面四种通知对应的所有位置</li>
</ul>
<p><img src="https://zylai-cloud-pic-1306915061.cos.ap-nanjing.myqcloud.com/images01/Spring.assets/image-20220728150243765.png" alt="image-20220728150243765"></p>
<h4 id="切面">切面</h4>
<p>封装横切关注点的类，通知的方法都写在切面类中</p>
<p><img src="https://zylai-cloud-pic-1306915061.cos.ap-nanjing.myqcloud.com/images01/Spring.assets/image-20220728150255542.png" alt="image-20220728150255542"></p>
<h4 id="目标">目标</h4>
<p>被代理的目标对象，比如计算器的实现类</p>
<h4 id="代理">代理</h4>
<p>代理对象</p>
<h4 id="连接点">连接点</h4>
<p>一个纯逻辑的概念：抽取横切关注点的位置，比如方法执行之前，方法捕获异常的时候等等。</p>
<p>连接点的作用：我们不但要抽取出来，还要套回去。</p>
<p><img src="https://zylai-cloud-pic-1306915061.cos.ap-nanjing.myqcloud.com/images01/Spring.assets/image-20220728150342960.png" alt="image-20220728150342960"></p>
<h4 id="切入点">切入点</h4>
<p>定位连接点的方式。</p>
<h4 id="总结：">总结：</h4>
<p>抽和套，抽取出来横切关注点，封装到切面中，就是一个通知。然后通过切入点找到连接点，把通知套到连接点的位置。</p>
<h2 id="6-AOP-基于注解的AOP">6 AOP-基于注解的AOP</h2>
<p><img src="https://zylai-cloud-pic-1306915061.cos.ap-nanjing.myqcloud.com/images01/Spring.assets/image-20220728150653683.png" alt="image-20220728150653683"></p>
<h3 id="6-1-技术说明">6.1 技术说明</h3>
<ul>
<li>动态代理（InvocationHandler）：JDK原生的实现方式，需要被代理的目标类必须实现接口。因为这个技术要求代理对象和目标对象实现同样的接口（兄弟两个拜把子模式）。</li>
<li>cglib：通过继承被代理的目标类（认干爹模式）实现代理，所以不需要目标类实现接口。</li>
<li>AspectJ：本质上是静态代理，将代理逻辑“织入”被代理的目标类编译得到的字节码文件，所以最终效果是动态的。weaver就是织入器。Spring只是借用了AspectJ中的注解。</li>
</ul>
<h3 id="6-2-配置">6.2 配置</h3>
<h5 id="maven依赖">maven依赖</h5>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!-- spring-aspects会帮我们传递过来aspectjweaver --&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-aspects<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">version</span>&gt;</span>5.3.1<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>
<h5 id="配置文件：">配置文件：</h5>
<ul>
<li>切面类和目标类都需要交给IOC容器管理</li>
<li>切面类必须通过@Aspect注解标识为一个切面</li>
<li>切面类必须通过@Aspect注解标识为一个切面</li>
</ul>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?xml version=<span class="string">&quot;1.0&quot;</span> encoding=<span class="string">&quot;UTF-8&quot;</span>?&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">beans</span> <span class="attr">xmlns</span>=<span class="string">&quot;http://www.springframework.org/schema/beans&quot;</span></span></span><br><span class="line"><span class="tag">       <span class="attr">xmlns:xsi</span>=<span class="string">&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</span></span></span><br><span class="line"><span class="tag">       <span class="attr">xmlns:context</span>=<span class="string">&quot;http://www.springframework.org/schema/context&quot;</span></span></span><br><span class="line"><span class="tag">       <span class="attr">xmlns:aop</span>=<span class="string">&quot;http://www.springframework.org/schema/aop&quot;</span></span></span><br><span class="line"><span class="tag">       <span class="attr">xsi:schemaLocation</span>=<span class="string">&quot;http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd&quot;</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">&lt;!--</span></span><br><span class="line"><span class="comment">    AOP的注意事项：</span></span><br><span class="line"><span class="comment">    切面类和目标类都需要交给IOC容器管理</span></span><br><span class="line"><span class="comment">    切面类必须通过@Aspect注解标识为一个切面</span></span><br><span class="line"><span class="comment">    在spring的配置文件中设置&lt;aop:aspectj-autoproxy/&gt;标签，开启基于注解的AOP功能</span></span><br><span class="line"><span class="comment">--&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">context:component-scan</span> <span class="attr">base-package</span>=<span class="string">&quot;com.zylai.spring.aop.annotation&quot;</span>/&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">&lt;!--开启基于注解的AOP功能--&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">aop:aspectj-autoproxy</span>/&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">beans</span>&gt;</span></span><br></pre></td></tr></table></figure>
<h3 id="6-3-切面类（重点）">6.3 切面类（重点）</h3>
<ol>
<li>
<p>在切面中，需要通过指定的注解将方法标识为通知方法</p>
<ul>
<li>@Before：前置通知，在目标方法执行之前执行</li>
<li>@After：后置通知，在目标对象方法的finally子句中执行</li>
<li>@AfterReturning：返回通知，在目标对象方法返回值之后执行</li>
<li>@AfterThrowing：异常通知，在目标对象方法的catch子句中执行</li>
</ul>
</li>
<li>
<p>切入点表达式：设置在表示通知的注解的value属性中</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">* &quot;execution(public int com.zylai.spring.aop.annotation.CalculatorImpl.add(int,int))&quot;</span><br><span class="line">* &quot;execution(* com.zylai.spring.aop.annotation.*.*(..))&quot;</span><br><span class="line">* 第一个*表示任意的访问修饰符和返回值类型</span><br><span class="line">* 第二个*表示包下所有的类</span><br><span class="line">* 第三个*表示类中任意的方法</span><br><span class="line">* ..表示任意的参数列表</span><br></pre></td></tr></table></figure>
</li>
<li>
<p>重用连接点表达式</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">* //声明一个公共的切入点表达式</span><br><span class="line">* @Pointcut(&quot;execution(* com.zylai.spring.aop.annotation.CalculatorImpl.*(..))&quot;)</span><br><span class="line">* public void pointCut()&#123;&#125;</span><br><span class="line">* 使用方式：  @After(&quot;pointCut()&quot;)</span><br></pre></td></tr></table></figure>
</li>
<li>
<p>重用连接点表达式</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">* 在通知方法的参数位置，设置JoinPoint类型的参数，就可以获取连接点所对应的方法信息</span><br><span class="line">*  //获取连接点对应方法的签名信息</span><br><span class="line">*  Signature signature = joinPoint.getSignature();</span><br><span class="line">*  //获取连接点所对应的参数</span><br><span class="line">*  Object[] args = joinPoint.getArgs();</span><br></pre></td></tr></table></figure>
</li>
<li>
<p>切面的优先级</p>
<figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">*  可以通过@Order注解的value属性设置优先级，默认值为Integer.MAX</span><br><span class="line">*  value值越小优先级越高</span><br></pre></td></tr></table></figure>
</li>
</ol>
<p>总的：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br></pre></td><td class="code"><pre><span class="line">* <span class="number">1.</span> 在切面中，需要通过指定的注解将方法标识为通知方法</span><br><span class="line"></span><br><span class="line">*</span><br><span class="line">* <span class="number">2.</span> 切入点表达式：设置在表示通知的注解的value属性中</span><br><span class="line">* <span class="string">&quot;execution(public int com.zylai.spring.aop.annotation.CalculatorImpl.add(int,int))&quot;</span></span><br><span class="line">* <span class="string">&quot;execution(* com.zylai.spring.aop.annotation.*.*(..))&quot;</span></span><br><span class="line">* 第一个*表示任意的访问修饰符和返回值类型</span><br><span class="line">* 第二个*表示包下所有的类</span><br><span class="line">* 第三个*表示类中任意的方法</span><br><span class="line">* ..表示任意的参数列表</span><br><span class="line">*</span><br><span class="line">* <span class="number">3.</span>重用连接点表达式</span><br><span class="line">* <span class="comment">//声明一个公共的切入点表达式</span></span><br><span class="line">* <span class="meta">@Pointcut(&quot;execution(* com.zylai.spring.aop.annotation.CalculatorImpl.*(..))&quot;)</span></span><br><span class="line">* <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">pointCut</span><span class="params">()</span>&#123;&#125;</span><br><span class="line">* 使用方式：  <span class="meta">@After(&quot;pointCut()&quot;)</span></span><br><span class="line">*</span><br><span class="line">*</span><br><span class="line">* <span class="number">4.</span> 获取连接点信息</span><br><span class="line">* 在通知方法的参数位置，设置JoinPoint类型的参数，就可以获取连接点所对应的方法信息</span><br><span class="line">*  <span class="comment">//获取连接点对应方法的签名信息</span></span><br><span class="line">*  <span class="type">Signature</span> <span class="variable">signature</span> <span class="operator">=</span> joinPoint.getSignature();</span><br><span class="line">*  <span class="comment">//获取连接点所对应的参数</span></span><br><span class="line">*  Object[] args = joinPoint.getArgs();</span><br><span class="line">*</span><br><span class="line">*  <span class="number">5.</span>切面的优先级</span><br><span class="line">*  可以通过<span class="meta">@Order</span>注解的value属性设置优先级，默认值为Integer.MAX</span><br><span class="line">*  value值越小优先级越高</span><br><span class="line"></span><br><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="meta">@Aspect</span><span class="comment">//将当前组件表示为切面</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">LoggerAspect</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Pointcut(&quot;execution(* com.zylai.spring.aop.annotation.CalculatorImpl.*(..))&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">pointCut</span><span class="params">()</span>&#123;&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">//    @Before(&quot;execution(public int com.zylai.spring.aop.annotation.CalculatorImpl.add(int,int))&quot;)</span></span><br><span class="line">    <span class="comment">//表示这个类下所有的方法，用*表示所有，参数列表用..表示所有的参数列表</span></span><br><span class="line"><span class="comment">//    @Before(&quot;execution(* com.zylai.spring.aop.annotation.CalculatorImpl.*(..))&quot;)</span></span><br><span class="line">    <span class="meta">@Before(&quot;pointCut()&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">beforeAdviceMethod</span><span class="params">(JoinPoint joinPoint)</span>&#123;</span><br><span class="line">        <span class="comment">//获取连接点对应方法的签名信息（签名信息就是方法的声明信息）</span></span><br><span class="line">        <span class="type">Signature</span> <span class="variable">signature</span> <span class="operator">=</span> joinPoint.getSignature();</span><br><span class="line">        <span class="comment">//获取连接点所对应的参数</span></span><br><span class="line">        Object[] args = joinPoint.getArgs();</span><br><span class="line">        System.out.println(<span class="string">&quot;LoggerAspect，前置通知，方法：&quot;</span>+signature.getName()+<span class="string">&quot;,参数：&quot;</span>+ Arrays.toString(args));</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@After(&quot;pointCut()&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">afterAdviceMethod</span><span class="params">(JoinPoint joinPoint)</span>&#123;</span><br><span class="line">        <span class="comment">//获取连接点对应方法的签名信息（签名信息就是方法的声明信息）</span></span><br><span class="line">        <span class="type">Signature</span> <span class="variable">signature</span> <span class="operator">=</span> joinPoint.getSignature();</span><br><span class="line">        System.out.println(<span class="string">&quot;LoggerAspect，后置通知，方法：&quot;</span>+signature.getName()+<span class="string">&quot;，执行完毕&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//在返回通知中若要获取目标对象方法的返回值，只需要通过注解的returning属性值</span></span><br><span class="line">    <span class="comment">//就可以将通知方法的某个参数指定为接收目标对象方法的返回值</span></span><br><span class="line">    <span class="meta">@AfterReturning(value = &quot;pointCut()&quot;,returning = &quot;result&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">afterReturningAdviceMethod</span><span class="params">(JoinPoint joinPoint, Object result)</span>&#123;</span><br><span class="line">        <span class="type">Signature</span> <span class="variable">signature</span> <span class="operator">=</span> joinPoint.getSignature();</span><br><span class="line">        System.out.println(<span class="string">&quot;LoggerAspect，返回通知，方法：&quot;</span>+signature.getName()+<span class="string">&quot;，结果：&quot;</span>+result);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//在返回通知中若要获取目标对象方法的异常，只需要通过注解的throwing属性值</span></span><br><span class="line">    <span class="comment">//就可以将通知方法的某个参数指定为接收目标对象方法出现的异常</span></span><br><span class="line">    <span class="meta">@AfterThrowing(value = &quot;pointCut()&quot;,throwing = &quot;ex&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">afterThrowingAdviceMethod</span><span class="params">(JoinPoint joinPoint,Throwable ex)</span>&#123;</span><br><span class="line">        <span class="type">Signature</span> <span class="variable">signature</span> <span class="operator">=</span> joinPoint.getSignature();</span><br><span class="line">        System.out.println(<span class="string">&quot;LoggerAspect，异常通知，方法：&quot;</span>+signature.getName()</span><br><span class="line">        +<span class="string">&quot;异常：&quot;</span>+ex);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="meta">@Around(&quot;pointCut()&quot;)</span></span><br><span class="line">    <span class="comment">//环绕通知的方法返回值一定要和目标方法的返回值一致</span></span><br><span class="line">    <span class="keyword">public</span> Object <span class="title function_">aroundAdviceMethod</span><span class="params">(ProceedingJoinPoint joinPoint)</span>&#123;</span><br><span class="line">        <span class="type">Object</span> <span class="variable">result</span> <span class="operator">=</span> <span class="literal">null</span>;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;环绕通知--&gt;前置通知&quot;</span>);</span><br><span class="line">            <span class="comment">//表示目标对象方法的执行</span></span><br><span class="line">            result = joinPoint.proceed();</span><br><span class="line">            System.out.println(<span class="string">&quot;环绕通知--&gt;返回通知&quot;</span>);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Throwable throwable) &#123;</span><br><span class="line">            throwable.printStackTrace();</span><br><span class="line">            System.out.println(<span class="string">&quot;环绕通知--&gt;异常通知&quot;</span>);</span><br><span class="line">        &#125;<span class="keyword">finally</span> &#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;环绕通知--&gt;后置通知&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> result;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h2 id="7-声明式事务">7 声明式事务</h2>
<blockquote>
<p>在Spring中，提供了封装了jdbc的JdbcTemplate，在之后的事务模块中，我们使用JdbcTemplate执行SQL</p>
</blockquote>
<h3 id="4-1-JdbcTemplate">4.1 JdbcTemplate</h3>
<h4 id="4-1-1-配置">4.1.1 配置</h4>
<p>maven</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!-- Spring 持久化层支持jar包 --&gt;</span></span><br><span class="line"><span class="comment">&lt;!-- Spring 在执行持久化层操作、与持久化层技术进行整合过程中，需要使用orm、jdbc、tx三个</span></span><br><span class="line"><span class="comment">jar包 --&gt;</span></span><br><span class="line"><span class="comment">&lt;!-- 导入 orm 包就可以通过 Maven 的依赖传递性把其他两个也导入 --&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-orm<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">version</span>&gt;</span>5.3.1<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>配置文件：</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!--引入jdbc.properties，之后可以通过$&#123;key&#125;的方式访问value--&gt;</span></span><br><span class="line"><span class="comment">&lt;!--这里的context标签，注意上面引入的--&gt;</span></span><br><span class="line"><span class="comment">&lt;!--在web项目中，有两种路径，一个是类路径，一个是web资源路径--&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">context:property-placeholder</span> <span class="attr">location</span>=<span class="string">&quot;classpath:jdbc.properties&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">context:property-placeholder</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;dataSource&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.alibaba.druid.pool.DruidDataSource&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;driverClassName&quot;</span> <span class="attr">value</span>=<span class="string">&quot;$&#123;jdbc.driver&#125;&quot;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;url&quot;</span> <span class="attr">value</span>=<span class="string">&quot;$&#123;jdbc.url&#125;&quot;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;username&quot;</span> <span class="attr">value</span>=<span class="string">&quot;$&#123;jdbc.username&#125;&quot;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;password&quot;</span> <span class="attr">value</span>=<span class="string">&quot;$&#123;jdbc.password&#125;&quot;</span>/&gt;</span></span><br><span class="line">    <span class="comment">&lt;!--&lt;property name=&quot;initialSize&quot; value=&quot;$&#123;initialSize&#125;&quot;/&gt;--&gt;</span></span><br><span class="line">    <span class="comment">&lt;!--&lt;property name=&quot;maxActive&quot; value=&quot;$&#123;maxActive&#125;&quot;/&gt;--&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;jdbcTemplate&quot;</span> <span class="attr">class</span>=<span class="string">&quot;org.springframework.jdbc.core.JdbcTemplate&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;dataSource&quot;</span> <span class="attr">ref</span>=<span class="string">&quot;dataSource&quot;</span>/&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br></pre></td></tr></table></figure>
<h4 id="4-1-2-使用-在Spring中进行测试-🎾">4.1.2 使用(在Spring中进行测试)🎾</h4>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//指定当前测试类在spring的测试环境中执行，此时就可以通过注入的方法直接获取IOC容器的bean</span></span><br><span class="line"><span class="meta">@RunWith(SpringJUnit4ClassRunner.class)</span></span><br><span class="line"><span class="comment">//设置Spring测试环境的配置文件</span></span><br><span class="line"><span class="meta">@ContextConfiguration(&quot;classpath:spring-jdbc.xml&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">JdbcTemplateTest</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Autowired</span></span><br><span class="line">    <span class="keyword">private</span> JdbcTemplate jdbcTemplate;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Test</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">testInsert</span><span class="params">()</span>&#123;</span><br><span class="line">        <span class="type">String</span> <span class="variable">sql</span> <span class="operator">=</span> <span class="string">&quot;insert into t_user values(null,?,?,?,?,?)&quot;</span>;</span><br><span class="line">        <span class="type">int</span> <span class="variable">update</span> <span class="operator">=</span> jdbcTemplate.update(sql, <span class="string">&quot;root&quot;</span>, <span class="string">&quot;123&quot;</span>, <span class="number">23</span>, <span class="string">&quot;女&quot;</span>, <span class="string">&quot;123@163.com&quot;</span>);</span><br><span class="line">        System.out.println(update);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Test</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">testGetUserById</span><span class="params">()</span>&#123;</span><br><span class="line">        <span class="type">String</span> <span class="variable">sql</span> <span class="operator">=</span> <span class="string">&quot;select * from t_user where id = ?&quot;</span>;</span><br><span class="line">        <span class="type">User</span> <span class="variable">user</span> <span class="operator">=</span> jdbcTemplate.queryForObject(sql, <span class="keyword">new</span> <span class="title class_">BeanPropertyRowMapper</span>&lt;&gt;(User.class), <span class="number">1</span>);</span><br><span class="line">        System.out.println(user);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Test</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">testGetAllUser</span><span class="params">()</span>&#123;</span><br><span class="line">        <span class="type">String</span> <span class="variable">sql</span> <span class="operator">=</span> <span class="string">&quot;select * from t_user&quot;</span>;</span><br><span class="line">        List&lt;User&gt; list = jdbcTemplate.query(sql, <span class="keyword">new</span> <span class="title class_">BeanPropertyRowMapper</span>&lt;&gt;(User.class));</span><br><span class="line">        System.out.println(list);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Test</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">testGetCount</span><span class="params">()</span>&#123;</span><br><span class="line">        <span class="type">String</span> <span class="variable">sql</span> <span class="operator">=</span> <span class="string">&quot;select count(*) from t_user&quot;</span>;</span><br><span class="line">        <span class="type">Integer</span> <span class="variable">count</span> <span class="operator">=</span> jdbcTemplate.queryForObject(sql, Integer.class);</span><br><span class="line">        System.out.println(count);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="4-2-声明式事务的概念">4.2 声明式事务的概念</h3>
<h4 id="4-2-1-编程式事务">4.2.1 编程式事务</h4>
<p><img src="https://zylai-cloud-pic-1306915061.cos.ap-nanjing.myqcloud.com/images01/Spring.assets/image-20220728153210291.png" alt="image-20220728153210291"></p>
<h4 id="4-2-2-声明式事务">4.2.2 声明式事务</h4>
<p>既然事务控制的代码有规律可循，代码的结构基本是确定的，所以框架就可以将固定模式的代码抽取出来，进行相关的封装。</p>
<p>封装起来的好处：</p>
<ul>
<li>好处1：提高开发效率</li>
<li>好处2：消除了冗余的代码</li>
<li>好处3：框架会综合考虑相关领域中在实际开发环境下有可能遇到的各种问题，进行了健壮性、性能等各个方面的优化</li>
</ul>
<p>编程式：自己写代码实现功能<br>
声明式：通过配置让框架实现功能</p>
<h3 id="4-3-基于注解的声明式事务">4.3 基于注解的声明式事务</h3>
<h4 id="场景模拟">场景模拟</h4>
<p>用户购买图书，先查询图书的价格，再更新图书的库存和用户的余额<br>
假设用户id为1的用户，购买id为1的图书<br>
用户余额为50，而图书价格为80<br>
购买图书之后，用户的余额为-30，数据库中余额字段设置了无符号，因此无法将-30插入到余额字段<br>
此时执行sql语句会抛出SQLException</p>
<h4 id="加入事务">加入事务</h4>
<ol>
<li>配置事务管理器，并且加上数据源属性</li>
<li>开启事务的注解驱动</li>
</ol>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">beans</span> <span class="attr">xmlns</span>=<span class="string">&quot;http://www.springframework.org/schema/beans&quot;</span></span></span><br><span class="line"><span class="tag">       <span class="attr">xmlns:xsi</span>=<span class="string">&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</span></span></span><br><span class="line"><span class="tag">       <span class="attr">xmlns:context</span>=<span class="string">&quot;http://www.springframework.org/schema/context&quot;</span> <span class="attr">xmlns:tx</span>=<span class="string">&quot;http://www.springframework.org/schema/tx&quot;</span></span></span><br><span class="line"><span class="tag">       <span class="attr">xsi:schemaLocation</span>=<span class="string">&quot;http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd&quot;</span>&gt;</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">&lt;!--扫描组件--&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">context:component-scan</span> <span class="attr">base-package</span>=<span class="string">&quot;com.zylai.spring&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">context:component-scan</span>&gt;</span></span><br><span class="line">    <span class="comment">&lt;!-- 导入外部属性文件 --&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">context:property-placeholder</span> <span class="attr">location</span>=<span class="string">&quot;classpath:jdbc.properties&quot;</span> /&gt;</span></span><br><span class="line">    <span class="comment">&lt;!-- 配置数据源 --&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;druidDataSource&quot;</span> <span class="attr">class</span>=<span class="string">&quot;com.alibaba.druid.pool.DruidDataSource&quot;</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;url&quot;</span> <span class="attr">value</span>=<span class="string">&quot;$&#123;jdbc.url&#125;&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;driverClassName&quot;</span> <span class="attr">value</span>=<span class="string">&quot;$&#123;jdbc.driver&#125;&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;username&quot;</span> <span class="attr">value</span>=<span class="string">&quot;$&#123;jdbc.username&#125;&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;password&quot;</span> <span class="attr">value</span>=<span class="string">&quot;$&#123;jdbc.password&#125;&quot;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br><span class="line">    <span class="comment">&lt;!-- 配置 JdbcTemplate --&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;jdbcTemplate&quot;</span> <span class="attr">class</span>=<span class="string">&quot;org.springframework.jdbc.core.JdbcTemplate&quot;</span>&gt;</span></span><br><span class="line">        <span class="comment">&lt;!-- 装配数据源 --&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;dataSource&quot;</span> <span class="attr">ref</span>=<span class="string">&quot;druidDataSource&quot;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">&lt;!--    配置事务管理器--&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">&quot;transactionManager&quot;</span> <span class="attr">class</span>=<span class="string">&quot;org.springframework.jdbc.datasource.DataSourceTransactionManager&quot;</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">&quot;dataSource&quot;</span> <span class="attr">ref</span>=<span class="string">&quot;druidDataSource&quot;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">&lt;!--</span></span><br><span class="line"><span class="comment">    开启事务的注解驱动</span></span><br><span class="line"><span class="comment">    将使用@Transactional注解所标识的方法或类中所有的方法使用事务进行管理</span></span><br><span class="line"><span class="comment">    @Transactional注解在哪，连接点就在哪里</span></span><br><span class="line"><span class="comment">    transaction-manager属性设置事务管理器的id</span></span><br><span class="line"><span class="comment">    若事务管理器的id默认为transactionManager，则改属性可以不写</span></span><br><span class="line"><span class="comment">    --&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">tx:annotation-driven</span> <span class="attr">transaction-manager</span>=<span class="string">&quot;transactionManager&quot;</span>/&gt;</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;/<span class="name">beans</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>在需要进行事务操作的类或方法上加上注解即可</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Service</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">BookServiceImpl</span> <span class="keyword">implements</span> <span class="title class_">BookService</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Autowired</span></span><br><span class="line">    <span class="keyword">private</span> BookDao bookDao;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="meta">@Transactional</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">buyBook</span><span class="params">(Integer userId, Integer bookId)</span> &#123;</span><br><span class="line">        <span class="comment">//查询图书的价格</span></span><br><span class="line">        <span class="type">Integer</span> <span class="variable">price</span> <span class="operator">=</span> bookDao.getPriceByBookId(bookId);</span><br><span class="line"></span><br><span class="line">        <span class="comment">//更新图书的库存</span></span><br><span class="line">        bookDao.updateStock(bookId);</span><br><span class="line">        <span class="comment">//更新用户的余额</span></span><br><span class="line">        bookDao.updateBalance(userId,price);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>结果：如果更新图书的库存顺利执行，而更新用户余额执行失败，那么将会回滚事务，图书库存将会恢复。</p>
<h3 id="4-4-事务的属性">4.4 事务的属性</h3>
<h4 id="1、只读">1、只读</h4>
<ol>
<li>
<p>介绍</p>
<p>对一个查询操作来说，如果我们把它设置成只读，就能够明确告诉数据库，这个操作不涉及写操作。这样数据库就能够针对查询操作来进行优化</p>
</li>
<li>
<p>使用方式</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Transactional(readOnly = true)</span></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">buyBook</span><span class="params">(Integer userId, Integer bookId)</span> &#123;</span><br><span class="line">        <span class="comment">//查询图书的价格</span></span><br><span class="line">        <span class="type">Integer</span> <span class="variable">price</span> <span class="operator">=</span> bookDao.getPriceByBookId(bookId);</span><br><span class="line"></span><br><span class="line">        <span class="comment">//更新图书的库存</span></span><br><span class="line">        bookDao.updateStock(bookId);</span><br><span class="line">        <span class="comment">//更新用户的余额</span></span><br><span class="line">        bookDao.updateBalance(userId,price);</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>
</li>
<li>
<p>注意：</p>
<p>对增删改操作设置只读会抛出下面异常：<br>
Caused by: java.sql.SQLException: Connection is read-only. Queries leading to data modification are not allowed</p>
</li>
</ol>
<h4 id="2、超时">2、超时</h4>
<ol>
<li>
<p>介绍：</p>
<p>事务在执行过程中，有可能因为遇到某些问题，导致程序卡住，从而长时间占用数据库资源。而长时间占用资源，大概率是因为程序运行出现了问题（可能是Java程序或MySQL数据库或网络连接等等）。<br>
此时这个很可能出问题的程序应该被回滚，撤销它已做的操作，事务结束，把资源让出来，让其他正常程序可以执行。</p>
<p>概括来说就是一句话：超时回滚，释放资源。</p>
</li>
<li>
<p>使用方式：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Transactional(timeout = 3)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">buyBook</span><span class="params">(Integer bookId, Integer userId)</span> &#123;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">    TimeUnit.SECONDS.sleep(<span class="number">5</span>);</span><br><span class="line">    &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">    e.printStackTrace();</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//查询图书的价格</span></span><br><span class="line">    <span class="type">Integer</span> <span class="variable">price</span> <span class="operator">=</span> bookDao.getPriceByBookId(bookId);</span><br><span class="line">    <span class="comment">//更新图书的库存</span></span><br><span class="line">    bookDao.updateStock(bookId);</span><br><span class="line">    <span class="comment">//更新用户的余额</span></span><br><span class="line">    bookDao.updateBalance(userId, price);</span><br><span class="line">    <span class="comment">//System.out.println(1/0);</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
</li>
<li>
<p>观察结果<br>
执行过程中抛出异常：<br>
org.springframework.transaction.TransactionTimedOutException: Transaction timed out:<br>
deadline was Fri Jun 04 16:25:39 CST 2022</p>
</li>
</ol>
<h4 id="3、回滚策略">3、回滚策略</h4>
<p>声明式事务默认对于运行时异常都进行回滚，一般使用的是在此基础上加上不因为哪个异常而回滚</p>
<p>可以通过@Transactional中相关属性设置回滚策略<br>
rollbackFor属性：需要设置一个Class类型的对象<br>
rollbackForClassName属性：需要设置一个字符串类型的全类名<br>
noRollbackFor属性：需要设置一个Class类型的对象<br>
rollbackFor属性：需要设置一个字符串类型的全类名</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Transactional(noRollbackFor = ArithmeticException.class)</span></span><br><span class="line"><span class="comment">//@Transactional(noRollbackForClassName = &quot;java.lang.ArithmeticException&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">buyBook</span><span class="params">(Integer bookId, Integer userId)</span> &#123;</span><br><span class="line">    <span class="comment">//查询图书的价格</span></span><br><span class="line">    <span class="type">Integer</span> <span class="variable">price</span> <span class="operator">=</span> bookDao.getPriceByBookId(bookId);</span><br><span class="line">    <span class="comment">//更新图书的库存</span></span><br><span class="line">    bookDao.updateStock(bookId);</span><br><span class="line">    <span class="comment">//更新用户的余额</span></span><br><span class="line">    bookDao.updateBalance(userId, price);</span><br><span class="line">    System.out.println(<span class="number">1</span>/<span class="number">0</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h4 id="4、隔离级别">4、隔离级别</h4>
<p>数据库系统必须具有隔离并发运行各个事务的能力，使它们不会相互影响，避免各种并发问题。一个事务与其他事务隔离的程度称为隔离级别。SQL标准中规定了多种事务隔离级别，不同隔离级别对应不同的干扰程度，隔离级别越高，数据一致性就越好，但并发性越弱。</p>
<p>隔离级别一共有四种：</p>
<ul>
<li>
<p>读未提交：READ UNCOMMITTED<br>
允许Transaction01读取Transaction02未提交的修改。</p>
</li>
<li>
<p>读已提交：READ COMMITTED、<br>
要求Transaction01只能读取Transaction02已提交的修改。</p>
</li>
<li>
<p>可重复读：REPEATABLE READ<br>
确保Transaction01可以多次从一个字段中读取到相同的值，即Transaction01执行期间禁止其它事务对这个字段进行更新。</p>
</li>
<li>
<p>串行化：SERIALIZABLE<br>
确保Transaction01可以多次从一个表中读取到相同的行，在Transaction01执行期间，禁止其它事务对这个表进行添加、更新、删除操作。可以避免任何并发问题，但性能十分低下。</p>
</li>
</ul>
<p>各个隔离级别解决并发问题的能力见下表：</p>
<p><img src="https://zylai-cloud-pic-1306915061.cos.ap-nanjing.myqcloud.com/images01/Spring.assets/image-20220804183341710.png" alt="image-20220804183341710"></p>
<p>使用：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Transactional(isolation = Isolation.DEFAULT)</span><span class="comment">//使用数据库默认的隔离级别</span></span><br><span class="line"><span class="meta">@Transactional(isolation = Isolation.READ_UNCOMMITTED)</span><span class="comment">//读未提交</span></span><br><span class="line"><span class="meta">@Transactional(isolation = Isolation.READ_COMMITTED)</span><span class="comment">//读已提交</span></span><br><span class="line"><span class="meta">@Transactional(isolation = Isolation.REPEATABLE_READ)</span><span class="comment">//可重复读</span></span><br><span class="line"><span class="meta">@Transactional(isolation = Isolation.SERIALIZABLE)</span><span class="comment">//串行化</span></span><br></pre></td></tr></table></figure>
<h4 id="5、事务的传播">5、事务的传播</h4>
<p>简单来说：</p>
<p>结账，买两本书。</p>
<p>如果以结账时间为事务，第二本买失败，第一本一会回滚。</p>
<p>如果用买书本身的操作，就是能买几本就是几本。</p>
<p>详细介绍：</p>
<p>当事务方法被另一个事务方法调用时，必须指定事务应该如何传播。例如：方法可能继续在现有事务中运行，也可能开启一个新事务，并在自己的事务中运行。</p>
</article><div class="post-copyright"><div class="post-copyright__author"><span class="post-copyright-meta">文章作者: </span><span class="post-copyright-info"><a href="https://zhaoyunlai.gitee.io">zylai</a></span></div><div class="post-copyright__type"><span class="post-copyright-meta">文章链接: </span><span class="post-copyright-info"><a href="https://zhaoyunlai.gitee.io/posts/d438b6f1fced/">https://zhaoyunlai.gitee.io/posts/d438b6f1fced/</a></span></div><div class="post-copyright__notice"><span class="post-copyright-meta">版权声明: </span><span class="post-copyright-info">本博客所有文章除特别声明外，均采用 <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/" target="_blank">CC BY-NC-SA 4.0</a> 许可协议。转载请注明来自 <a href="https://zhaoyunlai.gitee.io" target="_blank">zylai</a>！</span></div></div><div class="tag_share"><div class="post-meta__tag-list"><a class="post-meta__tags" href="/tags/%E6%A1%86%E6%9E%B6/">框架</a><a class="post-meta__tags" href="/tags/Spring/">Spring</a><a class="post-meta__tags" href="/tags/Spring-Framework/">Spring Framework</a></div><div class="post_share"><div class="social-share" data-image="https://zylai-cloud-pic-1306915061.cos.ap-nanjing.myqcloud.com/images01/Spring.assets/image-20220724093300702.png" data-sites="facebook,twitter,wechat,weibo,qq"></div><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/butterfly-extsrc/sharejs/dist/css/share.min.css" media="print" onload="this.media='all'"><script src="https://cdn.jsdelivr.net/npm/butterfly-extsrc/sharejs/dist/js/social-share.min.js" defer></script></div></div><nav class="pagination-post" id="pagination"><div class="prev-post pull-left"><a href="/posts/97f98a11ca37/"><img class="prev-cover" src="https://zylai-cloud-pic-1306915061.cos.ap-nanjing.myqcloud.com/images01/SpringMVC.assets/SpringMVC-logo.png" onerror="onerror=null;src='/img/404.jpg'" alt="cover of previous post"><div class="pagination-info"><div class="label">上一篇</div><div class="prev_info">SpringMVC框架</div></div></a></div><div class="next-post pull-right"><a href="/posts/9cf7da51c067/"><img class="next-cover" src="https://zylai-cloud-pic-1306915061.cos.ap-nanjing.myqcloud.com/images01/mybatis.assets/mybatis-logo.png" onerror="onerror=null;src='/img/404.jpg'" alt="cover of next post"><div class="pagination-info"><div class="label">下一篇</div><div class="next_info">MyBatis框架</div></div></a></div></nav><div class="relatedPosts"><div class="headline"><i class="fas fa-thumbs-up fa-fw"></i><span>相关推荐</span></div><div class="relatedPosts-list"><div><a href="/posts/91d12734b70c/" title="SSM整合"><img class="cover" src="https://zylai-cloud-pic-1306915061.cos.ap-nanjing.myqcloud.com/images01/SSM%E6%95%B4%E5%90%88.assets/SSM-cover.webp" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2022-08-04</div><div class="title">SSM整合</div></div></a></div><div><a href="/posts/97f98a11ca37/" title="SpringMVC框架"><img class="cover" src="https://zylai-cloud-pic-1306915061.cos.ap-nanjing.myqcloud.com/images01/SpringMVC.assets/SpringMVC-logo.png" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2022-08-02</div><div class="title">SpringMVC框架</div></div></a></div><div><a href="/posts/9cf7da51c067/" title="MyBatis框架"><img class="cover" src="https://zylai-cloud-pic-1306915061.cos.ap-nanjing.myqcloud.com/images01/mybatis.assets/mybatis-logo.png" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2022-07-23</div><div class="title">MyBatis框架</div></div></a></div><div><a href="/posts/32afa3256671/" title="SpringBoot2自动装配原理以及入门使用"><img class="cover" src="https://zylai-cloud-pic-1306915061.cos.ap-nanjing.myqcloud.com/images01/SpringBoot-01.assets/springboot01.png" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2022-08-14</div><div class="title">SpringBoot2自动装配原理以及入门使用</div></div></a></div></div></div></div><div class="aside-content" id="aside-content"><div class="card-widget card-info"><div class="is-center"><div class="avatar-img"><img src="/img/avatar.jpg" onerror="this.onerror=null;this.src='/img/friend_404.gif'" alt="avatar"/></div><div class="author-info__name">zylai</div><div class="author-info__description">zylai && 管大虾の克星</div></div><div class="card-info-data site-data is-center"><a href="/archives/"><div class="headline">文章</div><div class="length-num">18</div></a><a href="/tags/"><div class="headline">标签</div><div class="length-num">14</div></a><a href="/categories/"><div class="headline">分类</div><div class="length-num">11</div></a></div><a id="card-info-btn" target="_blank" rel="noopener" href="https://github.com/zhaoyunlai"><i class="fab fa-github"></i><span>Follow Me</span></a><div class="card-info-social-icons is-center"><a class="social-icon" href="https://github.com/zhaoyunlai" target="_blank" title="Github"><i class="fab fa-github"></i></a><a class="social-icon" href="mailto:zylai0712@163.com" target="_blank" title="Email"><i class="fas fa-envelope"></i></a></div></div><div class="card-widget card-announcement"><div class="item-headline"><i class="fas fa-bullhorn fa-shake"></i><span>公告</span></div><div class="announcement_content">This is my blog</div></div><div class="sticky_layout"><div class="card-widget" id="card-toc"><div class="item-headline"><i class="fas fa-stream"></i><span>目录</span><span class="toc-percentage"></span></div><div class="toc-content"><ol class="toc"><li class="toc-item toc-level-1"><a class="toc-link"><span class="toc-text">Spring</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#1-Spring%E7%AE%80%E4%BB%8B%F0%9F%91%BE"><span class="toc-text">1 Spring简介👾</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#1-1-Spring%E6%A6%82%E8%BF%B0"><span class="toc-text">1.1 Spring概述</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#1-2-Spring-Framework"><span class="toc-text">1.2 Spring Framework</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#1-2-1-Spring-Framework%E7%89%B9%E6%80%A7"><span class="toc-text">1.2.1 Spring Framework特性</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#1-2-2-Spring-Framework%E4%BA%94%E5%A4%A7%E5%8A%9F%E8%83%BD%E6%A8%A1%E5%9D%97"><span class="toc-text">1.2.2 Spring Framework五大功能模块</span></a></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#2-IOC-IOC%E5%AE%B9%E5%99%A8%E6%80%9D%E6%83%B3"><span class="toc-text">2 IOC-IOC容器思想</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#IOC%E5%AE%B9%E5%99%A8%E6%80%9D%E6%83%B3"><span class="toc-text">IOC容器思想</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#IOC%E5%9C%A8Spring%E4%B8%AD%E7%9A%84%E5%AE%9E%E7%8E%B0"><span class="toc-text">IOC在Spring中的实现</span></a></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#3-IOC-%E5%9F%BA%E4%BA%8EXML%E6%96%87%E4%BB%B6%E7%AE%A1%E7%90%86Bean"><span class="toc-text">3 IOC-基于XML文件管理Bean</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#3-1-%E5%87%86%E5%A4%87%E5%B7%A5%E4%BD%9C"><span class="toc-text">3.1 准备工作</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#3-2-%E8%8E%B7%E5%8F%96bean"><span class="toc-text">3.2 获取bean</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#3-2-1-%E6%96%B9%E5%BC%8F%E4%B8%80%EF%BC%9A%E9%80%9A%E8%BF%87bean%E7%9A%84id"><span class="toc-text">3.2.1 方式一：通过bean的id</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#3-2-2-%E6%96%B9%E5%BC%8F%E4%BA%8C%EF%BC%9A%E9%80%9A%E8%BF%87%E7%B1%BB%E5%9E%8B%EF%BC%88%E7%B1%BB%E7%9A%84Class%E5%AF%B9%E8%B1%A1%EF%BC%89"><span class="toc-text">3.2.2 方式二：通过类型（类的Class对象）</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#3-2-3-%E6%96%B9%E5%BC%8F%E4%B8%89%EF%BC%9A%E9%80%9A%E8%BF%87%E7%B1%BB%E5%9E%8B%E5%92%8Cid"><span class="toc-text">3.2.3 方式三：通过类型和id</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#3-2-4-%E8%8E%B7%E5%8F%96bean%E7%9A%84%E6%96%B9%E5%BC%8F%E6%80%BB%E7%BB%93"><span class="toc-text">3.2.4 获取bean的方式总结</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#3-2-5-%E5%AF%B9%E4%BA%8E%E6%8E%A5%E5%8F%A3"><span class="toc-text">3.2.5 对于接口</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#3-2-6-%E6%A0%B9%E6%8D%AE%E7%B1%BB%E5%9E%8B%E8%8E%B7%E5%8F%96bean%E7%9A%84%E5%AE%9E%E8%B4%A8"><span class="toc-text">3.2.6 根据类型获取bean的实质</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#3-3-%E4%BE%9D%E8%B5%96%E6%B3%A8%E5%85%A5"><span class="toc-text">3.3 依赖注入</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#setter%E6%B3%A8%E5%85%A5%E5%92%8C%E6%9E%84%E9%80%A0%E5%99%A8%E6%B3%A8%E5%85%A5%E2%AD%90"><span class="toc-text">setter注入和构造器注入⭐</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#3-3-1-%E7%89%B9%E6%AE%8A%E5%80%BC%E5%A4%84%E7%90%86"><span class="toc-text">3.3.1 特殊值处理</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#3-3-2-%E7%B1%BB%E7%B1%BB%E5%9E%8B%E7%9A%84%E5%B1%9E%E6%80%A7%E8%B5%8B%E5%80%BC"><span class="toc-text">3.3.2 类类型的属性赋值</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#3-3-3-%E6%95%B0%E7%BB%84"><span class="toc-text">3.3.3 数组</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#3-3-4-list%E9%9B%86%E5%90%88"><span class="toc-text">3.3.4 list集合</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#3-3-5-map%E9%9B%86%E5%90%88"><span class="toc-text">3.3.5 map集合</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#3-3-6-p%E5%91%BD%E5%90%8D%E7%A9%BA%E9%97%B4"><span class="toc-text">3.3.6 p命名空间</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#3-4-%E7%AE%A1%E7%90%86%E6%95%B0%E6%8D%AE%E6%BA%90%E5%92%8C%E5%A4%96%E9%83%A8%E6%96%87%E4%BB%B6"><span class="toc-text">3.4  管理数据源和外部文件</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#%E5%8A%A0%E5%85%A5%E4%BE%9D%E8%B5%96"><span class="toc-text">加入依赖</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E5%88%9B%E5%BB%BAjdbc%E7%9A%84%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6"><span class="toc-text">创建jdbc的配置文件</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E9%85%8D%E7%BD%AEDataSource"><span class="toc-text">配置DataSource</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#3-5-bean%E7%9A%84%E4%BD%9C%E7%94%A8%E5%9F%9F"><span class="toc-text">3.5 bean的作用域</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#3-6-bean%E7%9A%84%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F"><span class="toc-text">3.6  bean的生命周期</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#3-7-%E5%B7%A5%E5%8E%82bean"><span class="toc-text">3.7  工厂bean</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#%E6%A6%82%E5%BF%B5"><span class="toc-text">概念</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E5%AE%9E%E7%8E%B0FactoryBean%E6%8E%A5%E5%8F%A3"><span class="toc-text">实现FactoryBean接口</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#3-8-%E8%87%AA%E5%8A%A8%E8%A3%85%E9%85%8D%E2%AD%90"><span class="toc-text">3.8  自动装配⭐</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#%E6%A6%82%E5%BF%B5-v2"><span class="toc-text">概念</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E5%AE%9E%E7%8E%B0"><span class="toc-text">实现</span></a></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#4-IOC-%E5%9F%BA%E4%BA%8E%E6%B3%A8%E8%A7%A3%E7%AE%A1%E7%90%86Bean"><span class="toc-text">4 IOC-基于注解管理Bean</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#4-1-%E4%BD%BF%E7%94%A8%E6%B3%A8%E8%A7%A3%E6%B3%A8%E5%86%8Cbean%E7%BB%84%E4%BB%B6"><span class="toc-text">4.1 使用注解注册bean组件</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#4-2-%E6%89%AB%E6%8F%8F%E7%BB%84%E4%BB%B6"><span class="toc-text">4.2  扫描组件</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#4-3-Autowired%E8%87%AA%E5%8A%A8%E8%A3%85%E9%85%8D"><span class="toc-text">4.3 @Autowired自动装配</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#4-3-1-%E8%83%BD%E5%A4%9F%E6%A0%87%E8%AF%86%E7%9A%84%E4%BD%8D%E7%BD%AE"><span class="toc-text">4.3.1 能够标识的位置</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#4-3-2-%E6%B3%A8%E5%85%A5%E7%9A%84%E6%96%B9%E5%BC%8F"><span class="toc-text">4.3.2 注入的方式</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#4-4-%E4%BE%8B%E5%AD%90"><span class="toc-text">4.4 例子</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#5-AOP-%E6%A6%82%E5%BF%B5"><span class="toc-text">5 AOP-概念</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#5-1-%E4%BB%A3%E7%90%86%E6%A8%A1%E5%BC%8F"><span class="toc-text">5.1 代理模式</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#5-1-1-%E6%A6%82%E5%BF%B5"><span class="toc-text">5.1.1 概念</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#5-1-2-%E9%9D%99%E6%80%81%E4%BB%A3%E7%90%86"><span class="toc-text">5.1.2 静态代理</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#5-1-3-%E5%8A%A8%E6%80%81%E4%BB%A3%E7%90%86"><span class="toc-text">5.1.3 动态代理</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#5-2-AOP%E6%A6%82%E5%BF%B5%E5%8F%8A%E7%9B%B8%E5%85%B3%E6%9C%AF%E8%AF%AD"><span class="toc-text">5.2 AOP概念及相关术语</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#AOP"><span class="toc-text">AOP</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E6%A8%AA%E5%88%87%E5%85%B3%E6%B3%A8%E7%82%B9"><span class="toc-text">横切关注点</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E9%80%9A%E7%9F%A5"><span class="toc-text">通知</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E5%88%87%E9%9D%A2"><span class="toc-text">切面</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E7%9B%AE%E6%A0%87"><span class="toc-text">目标</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E4%BB%A3%E7%90%86"><span class="toc-text">代理</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E8%BF%9E%E6%8E%A5%E7%82%B9"><span class="toc-text">连接点</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E5%88%87%E5%85%A5%E7%82%B9"><span class="toc-text">切入点</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E6%80%BB%E7%BB%93%EF%BC%9A"><span class="toc-text">总结：</span></a></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#6-AOP-%E5%9F%BA%E4%BA%8E%E6%B3%A8%E8%A7%A3%E7%9A%84AOP"><span class="toc-text">6 AOP-基于注解的AOP</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#6-1-%E6%8A%80%E6%9C%AF%E8%AF%B4%E6%98%8E"><span class="toc-text">6.1 技术说明</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#6-2-%E9%85%8D%E7%BD%AE"><span class="toc-text">6.2 配置</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#maven%E4%BE%9D%E8%B5%96"><span class="toc-text">maven依赖</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%EF%BC%9A"><span class="toc-text">配置文件：</span></a></li></ol></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#6-3-%E5%88%87%E9%9D%A2%E7%B1%BB%EF%BC%88%E9%87%8D%E7%82%B9%EF%BC%89"><span class="toc-text">6.3 切面类（重点）</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#7-%E5%A3%B0%E6%98%8E%E5%BC%8F%E4%BA%8B%E5%8A%A1"><span class="toc-text">7 声明式事务</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#4-1-JdbcTemplate"><span class="toc-text">4.1 JdbcTemplate</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#4-1-1-%E9%85%8D%E7%BD%AE"><span class="toc-text">4.1.1 配置</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#4-1-2-%E4%BD%BF%E7%94%A8-%E5%9C%A8Spring%E4%B8%AD%E8%BF%9B%E8%A1%8C%E6%B5%8B%E8%AF%95-%F0%9F%8E%BE"><span class="toc-text">4.1.2 使用(在Spring中进行测试)🎾</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#4-2-%E5%A3%B0%E6%98%8E%E5%BC%8F%E4%BA%8B%E5%8A%A1%E7%9A%84%E6%A6%82%E5%BF%B5"><span class="toc-text">4.2 声明式事务的概念</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#4-2-1-%E7%BC%96%E7%A8%8B%E5%BC%8F%E4%BA%8B%E5%8A%A1"><span class="toc-text">4.2.1 编程式事务</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#4-2-2-%E5%A3%B0%E6%98%8E%E5%BC%8F%E4%BA%8B%E5%8A%A1"><span class="toc-text">4.2.2 声明式事务</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#4-3-%E5%9F%BA%E4%BA%8E%E6%B3%A8%E8%A7%A3%E7%9A%84%E5%A3%B0%E6%98%8E%E5%BC%8F%E4%BA%8B%E5%8A%A1"><span class="toc-text">4.3 基于注解的声明式事务</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#%E5%9C%BA%E6%99%AF%E6%A8%A1%E6%8B%9F"><span class="toc-text">场景模拟</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E5%8A%A0%E5%85%A5%E4%BA%8B%E5%8A%A1"><span class="toc-text">加入事务</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#4-4-%E4%BA%8B%E5%8A%A1%E7%9A%84%E5%B1%9E%E6%80%A7"><span class="toc-text">4.4 事务的属性</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#1%E3%80%81%E5%8F%AA%E8%AF%BB"><span class="toc-text">1、只读</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#2%E3%80%81%E8%B6%85%E6%97%B6"><span class="toc-text">2、超时</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#3%E3%80%81%E5%9B%9E%E6%BB%9A%E7%AD%96%E7%95%A5"><span class="toc-text">3、回滚策略</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#4%E3%80%81%E9%9A%94%E7%A6%BB%E7%BA%A7%E5%88%AB"><span class="toc-text">4、隔离级别</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#5%E3%80%81%E4%BA%8B%E5%8A%A1%E7%9A%84%E4%BC%A0%E6%92%AD"><span class="toc-text">5、事务的传播</span></a></li></ol></li></ol></li></ol></li></ol></div></div><div class="card-widget card-recent-post"><div class="item-headline"><i class="fas fa-history"></i><span>最新文章</span></div><div class="aside-list"><div class="aside-list-item"><a class="thumbnail" href="/posts/22ef9dff46af/" title="移动互联网开发技术-第三次实验"><img src="https://zylai-cloud-pic-1306915061.cos.ap-nanjing.myqcloud.com/images01/%E7%B3%BB%E7%BB%9F%E8%AE%BE%E8%AE%A1.assets/sdnu-background2.jpg" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="移动互联网开发技术-第三次实验"/></a><div class="content"><a class="title" href="/posts/22ef9dff46af/" title="移动互联网开发技术-第三次实验">移动互联网开发技术-第三次实验</a><time datetime="2022-10-15T01:43:30.000Z" title="发表于 2022-10-15 09:43:30">2022-10-15</time></div></div><div class="aside-list-item"><a class="thumbnail" href="/posts/85838fb07a8b/" title="学生成长动态追踪系统-学生使用手册"><img src="https://zylai-cloud-pic-1306915061.cos.ap-nanjing.myqcloud.com/images01/%E7%B3%BB%E7%BB%9F%E8%AE%BE%E8%AE%A1.assets/sdnu-background2.jpg" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="学生成长动态追踪系统-学生使用手册"/></a><div class="content"><a class="title" href="/posts/85838fb07a8b/" title="学生成长动态追踪系统-学生使用手册">学生成长动态追踪系统-学生使用手册</a><time datetime="2022-09-25T11:43:30.000Z" title="发表于 2022-09-25 19:43:30">2022-09-25</time></div></div><div class="aside-list-item"><a class="thumbnail" href="/posts/896511b44bb7/" title="学生成长动态追踪系统-家长使用手册"><img src="https://zylai-cloud-pic-1306915061.cos.ap-nanjing.myqcloud.com/images01/%E7%B3%BB%E7%BB%9F%E8%AE%BE%E8%AE%A1.assets/sdnu-background2.jpg" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="学生成长动态追踪系统-家长使用手册"/></a><div class="content"><a class="title" href="/posts/896511b44bb7/" title="学生成长动态追踪系统-家长使用手册">学生成长动态追踪系统-家长使用手册</a><time datetime="2022-09-25T11:43:29.000Z" title="发表于 2022-09-25 19:43:29">2022-09-25</time></div></div><div class="aside-list-item"><a class="thumbnail" href="/posts/78afc3f0ab42/" title="Shiro权限安全框架的使用"><img src="https://zylai-cloud-pic-1306915061.cos.ap-nanjing.myqcloud.com/images01/shiro.assets/image-20220929162947122.png" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="Shiro权限安全框架的使用"/></a><div class="content"><a class="title" href="/posts/78afc3f0ab42/" title="Shiro权限安全框架的使用">Shiro权限安全框架的使用</a><time datetime="2022-09-18T11:43:29.000Z" title="发表于 2022-09-18 19:43:29">2022-09-18</time></div></div><div class="aside-list-item"><a class="thumbnail" href="/posts/e32230f09e09/" title="学生成长动态追踪系统"><img src="https://zylai-cloud-pic-1306915061.cos.ap-nanjing.myqcloud.com/images01/%E7%B3%BB%E7%BB%9F%E8%AE%BE%E8%AE%A1.assets/sdnu-background2.jpg" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="学生成长动态追踪系统"/></a><div class="content"><a class="title" href="/posts/e32230f09e09/" title="学生成长动态追踪系统">学生成长动态追踪系统</a><time datetime="2022-08-25T11:43:29.000Z" title="发表于 2022-08-25 19:43:29">2022-08-25</time></div></div></div></div></div></div></main><footer id="footer" style="background-image: url('https://zylai-cloud-pic-1306915061.cos.ap-nanjing.myqcloud.com/images01/Spring.assets/image-20220724093300702.png')"><div id="footer-wrap"><div class="copyright">&copy;2020 - 2022 By zylai</div><div class="framework-info"><span>框架 </span><a target="_blank" rel="noopener" href="https://hexo.io">Hexo</a><span class="footer-separator">|</span><span>主题 </span><a target="_blank" rel="noopener" href="https://github.com/jerryc127/hexo-theme-butterfly">Butterfly</a></div></div></footer></div><div id="rightside"><div id="rightside-config-hide"><button id="readmode" type="button" title="阅读模式"><i class="fas fa-book-open"></i></button><button id="darkmode" type="button" title="浅色和深色模式转换"><i class="fas fa-adjust"></i></button><button id="hide-aside-btn" type="button" title="单栏和双栏切换"><i class="fas fa-arrows-alt-h"></i></button></div><div id="rightside-config-show"><button id="rightside_config" type="button" title="设置"><i class="fas fa-cog fa-spin"></i></button><button class="close" id="mobile-toc-button" type="button" title="目录"><i class="fas fa-list-ul"></i></button><button id="go-up" type="button" title="回到顶部"><i class="fas fa-arrow-up"></i></button></div></div><div id="local-search"><div class="search-dialog"><nav class="search-nav"><span class="search-dialog-title">搜索</span><span id="loading-status"></span><button class="search-close-button"><i class="fas fa-times"></i></button></nav><div class="is-center" id="loading-database"><i class="fas fa-spinner fa-pulse"></i><span>  数据库加载中</span></div><div class="search-wrap"><div id="local-search-input"><div class="local-search-box"><input class="local-search-box--input" placeholder="搜索文章" type="text"/></div></div><hr/><div id="local-search-results"></div></div></div><div id="search-mask"></div></div><div><script src="/js/utils.js"></script><script src="/js/main.js"></script><script src="https://cdn.jsdelivr.net/npm/@fancyapps/ui/dist/fancybox.umd.min.js"></script><script src="/js/search/local-search.js"></script><div class="js-pjax"></div><script defer="defer" id="ribbon" src="https://cdn.jsdelivr.net/npm/butterfly-extsrc/dist/canvas-ribbon.min.js" size="150" alpha="0.6" zIndex="-1" mobile="false" data-click="true"></script><script async data-pjax src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script></div><!-- hexo injector body_end start --><script data-pjax>function electric_clock_injector_config(){
                var parent_div_git = document.getElementsByClassName('sticky_layout')[0];
                var item_html = '<div class="card-widget card-clock"><div class="card-glass"><div class="card-background"><div class="card-content"><div id="hexo_electric_clock"><img id="card-clock-loading" src="https://cdn.jsdelivr.net/gh/Zfour/Butterfly-clock/clock/images/weather/loading.gif" style="height: 120px; width: 100%;" data-ll-status="loading" class="entered loading"></div></div></div></div></div>';
                console.log('已挂载electric_clock')
                // parent_div_git.innerHTML=item_html+parent_div_git.innerHTML // 无报错，但不影响使用(支持pjax跳转)
                parent_div_git.insertAdjacentHTML("afterbegin",item_html) // 有报错，但不影响使用(支持pjax跳转)
            }if( document.getElementsByClassName('sticky_layout')[0] && (location.pathname ==='/'|| '/' ==='all')){

            electric_clock_injector_config()
        } </script><script src="https://pv.sohu.com/cityjson?ie=utf-8"></script><script data-pjax  src="https://cdn.jsdelivr.net/gh/Zfour/hexo-electric-clock@1.0.6/clock.js"></script><!-- hexo injector body_end end --></body></html>